magento2 checkout页面对shipping address指定字段添加自定义验证
magento2 checkout页面对shipping address指定字段添加自定义验证
接到客户需求,想要在用户输入street字段的时候,输入内容若包含P.O. BOX 则有相关提示:
首先想到的肯定是添加blur或者keyup事件进行输入监听,这样的话要不了几分钟就搞定了。
若遵循magento开发规范,则需要另外想法子,项目用了onestepcheckout插件,但是原理都是一样的,在主题或者自定义的module里面重写就行了。
首先用户点击place order的时候验证:
checkout_index_index:找到并且替换对应内容
<item name="additional-payment-validators" xsi:type="array"> <item name="component" xsi:type="string">uiComponent</item> <item name="children" xsi:type="array"> <!-- Additional payment validators here --> <item name="email-validator" xsi:type="array"> <item name="component" xsi:type="string">Aheadworks_OneStepCheckout/js/view/payment-method/email-validator</item> </item> <item name="agreements-validator" xsi:type="array"> <item name="component" xsi:type="string">Aheadworks_OneStepCheckout/js/view/checkout-agreements/validation</item> </item> <!--插入自定义验证器--> <item name="streetValidator" xsi:type="array"> <item name="component" xsi:type="string">Aheadworks_OneStepCheckout/js/view/streetValidator</item> </item> </item> </item>
streetValidator注册验证器器内容:
/** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define( [ &#39;uiComponent&#39;, &#39;Magento_Checkout/js/model/payment/additional-validators&#39;, &#39;Aheadworks_OneStepCheckout/js/model/streetValidator&#39; ], function (Component, additionalValidators, streetValidator) { &#39;use strict&#39;; additionalValidators.registerValidator(streetValidator); return Component.extend({}); } );
Aheadworks_OneStepCheckout/js/model/streetValidator.js文件内容:
define( [ &#39;jquery&#39;, &#39;Magento_Ui/js/model/messageList&#39;, &#39;Magento_Checkout/js/model/quote&#39; ], function ($,messageList,quote) { &#39;use strict&#39;; return { /** * Validate street not have po box * * @returns {boolean} */ validate: function() { var pass = false; //在这里添加自己的一些验证代码 //验证不通过返回错误信息 messageList.addErrorMessage({message: &#39;show message!&#39; }); return pass; } } );
验证不通过的效果:
添加street内容更改时触发事件,借鉴postcode验证方式:
Magento_Checkout/js/model/shipping-rates-validator.js
/** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define([ &#39;jquery&#39;, &#39;ko&#39;, &#39;Magento_Checkout/js/model/shipping-rates-validation-rules&#39;, &#39;Magento_Checkout/js/model/address-converter&#39;, &#39;Magento_Checkout/js/action/select-shipping-address&#39;, &#39;Magento_Checkout/js/model/postcode-validator&#39;, &#39;Magento_Checkout/js/model/default-validator&#39;, &#39;mage/translate&#39;, &#39;uiRegistry&#39;, &#39;Magento_Checkout/js/model/shipping-address/form-popup-state&#39;, &#39;Magento_Checkout/js/model/quote&#39; ], function ( $, ko, shippingRatesValidationRules, addressConverter, selectShippingAddress, postcodeValidator, defaultValidator, $t, uiRegistry, formPopUpState ) { &#39;use strict&#39;; var checkoutConfig = window.checkoutConfig, validators = [], observedElements = [], postcodeElement = null, postcodeElementName = &#39;postcode&#39;, streetElementName = &#39;street.0&#39;,//定义验证字段元素名称 streetElementFormName = &#39;street[0]&#39;, streetElement = null; validators.push(defaultValidator); return { validateAddressTimeout: 0, validateDelay: 2000, /**这个方法会注册各个shipping method插件的验证器,比如ups,free shipping tablerate等 * @param {String} carrier * @param {Object} validator */ registerValidator: function (carrier, validator) { //checkoutConfig里面保存了很多配置信息,这里取的是已经开启的shipping method的名称; if (checkoutConfig.activeCarriers.indexOf(carrier) !== -1) { //注册shipping method提供的验证器,前提是该shipping method已经开启; validators.push(validator); } }, /**验证数据 * @param {Object} address * @return {Boolean} */ validateAddressData: function (address) { return validators.some(function (validator) { return validator.validate(address); }); }, /** * 初始化字段,对应字段绑定事件 * * @param {String} formPath */ initFields: function (formPath) { var self = this, //elements通过shippingRatesValidationRules里面获取各个shipping method提供的rules返回的字段,我这里因为跟shipping method无关就直接把street插入进去了。 elements = shippingRatesValidationRules.getObservableFields(); if ($.inArray(postcodeElementName, elements) === -1) { // Add postcode field to observables if not exist for zip code validation support elements.push(postcodeElementName); } //在这里添加street字段 if ($.inArray(streetElementName, elements) === -1) { // Add street field to observables if not exist elements.push(streetElementName); } $.each(elements, function (index, field) { uiRegistry.async(formPath + &#39;.&#39; + field)(self.doElementBinding.bind(self)); }); }, /** * 将请求绑定到表单元素 * * @param {Object} element * @param {Boolean} force * @param {Number} delay */ doElementBinding: function (element, force, delay) { var observableFields = shippingRatesValidationRules.getObservableFields(); if (element && (observableFields.indexOf(element.index) !== -1 || force)) { if (element.index !== postcodeElementName) { this.bindHandler(element, delay); } //这里因为street是数组格式,index=0 所以我换了inputName方式判断,模拟postcode的处理方式 if (element.inputName !== streetElementFormName) { this.bindHandler(element, delay); } } if (element.index === postcodeElementName) { this.bindHandler(element, delay); postcodeElement = element; } if (element.inputName === streetElementFormName) { this.bindHandler(element, delay); streetElement = element; } }, /** * @param {*} elements * @param {Boolean} force * @param {Number} delay */ bindChangeHandlers: function (elements, force, delay) { var self = this; $.each(elements, function (index, elem) { self.doElementBinding(elem, force, delay); }); }, /** * @param {Object} element * @param {Number} delay */ bindHandler: function (element, delay) { var self = this; delay = typeof delay === &#39;undefined&#39; ? self.validateDelay : delay; if (element.component.indexOf(&#39;/group&#39;) !== -1) { $.each(element.elems(), function (index, elem) { self.bindHandler(elem); }); } else { element.on(&#39;value&#39;, function () { if (!formPopUpState.isVisible()) { clearTimeout(self.validateAddressTimeout); self.validateAddressTimeout = setTimeout(function () { self.postcodeValidation(); self.validateFields(); self.streetValidation();//模拟postcode验证,添加了自己的验证方法 }, delay); } }); observedElements.push(element); } }, streetValidation: function (){ streetElement.error(null); //添加自定义验证内容 if(!pass){ streetElement.error(&#39;PLEASE NOTE: WE DO NOT SHIP TO P.O. BOXES!&#39;); } return pass; }, /** * @return {*} */ postcodeValidation: function () { var countryId = $(&#39;select[name="country_id"]&#39;).val(), validationResult, warnMessage; if (postcodeElement == null || postcodeElement.value() == null) { return true; } postcodeElement.warn(null); validationResult = postcodeValidator.validate(postcodeElement.value(), countryId); if (!validationResult) { warnMessage = $t(&#39;Provided Zip/Postal Code seems to be invalid.&#39;); if (postcodeValidator.validatedPostCodeExample.length) { warnMessage += $t(&#39; Example: &#39;) + postcodeValidator.validatedPostCodeExample.join(&#39;; &#39;) + &#39;. &#39;; } warnMessage += $t(&#39;If you believe it is the right one you can ignore this notice.&#39;); postcodeElement.warn(warnMessage); } return validationResult; }, /** * Convert form data to quote address and validate fields for shipping rates */ validateFields: function () { var addressFlat = addressConverter.formDataProviderToFlatData( this.collectObservedData(), &#39;shippingAddress&#39; ), address; if (this.validateAddressData(addressFlat)) { addressFlat = uiRegistry.get(&#39;checkoutProvider&#39;).shippingAddress; address = addressConverter.formAddressDataToQuoteAddress(addressFlat); selectShippingAddress(address); } }, /** * Collect observed fields data to object * * @returns {*} */ collectObservedData: function () { var observedValues = {}; $.each(observedElements, function (index, field) { observedValues[field.dataScope] = field.value(); }); return observedValues; } }; });
内容更改就会触发验证:
最后:一定要注意位置和命名,遇到问题浏览器断点调试,熟悉处理流程以及对应数据变化,这里可能不是最好的和最规范的操作。如果有更好的方法,希望指出来改进改进。