In Magento 2, at the Checkout, some fields are required. But for some reason the Postal code (postcode) field always has a red border and the 'required' notification below it. How do I remove this? Can't find it in any template.
2 Answers
We will begin with a research that will lead to a simple solution without any modifications in a code. If you don't have time to read the full answer, scroll down to the latest paragraphs with the answer.
The magento/module-ui/view/base/web/js/form/element/post-code.js
element has built-in validation right in the code:
<script>
/**
* @param {String} value
*/
update: function (value) {
var country = registry.get(this.parentName + '.' + 'country_id'),
options = country.indexedOptions,
option;
if (!value) {
return;
}
option = options[value];
if (option['is_zipcode_optional']) {
this.error(false);
this.validation = _.omit(this.validation, 'required-entry');
} else {
this.validation['required-entry'] = true;
}
this.required(!option['is_zipcode_optional']);
}
</script>
That's why it is enabled all the time. The fastest solution is to rewrite this element and add your own code that will be inherited from the default. You can do this in the following way:
The element itself for the post code is declared here:
magento/module-checkout/view/frontend/layout/checkout_index_index.xml
and has the following view:
<item name="postcode" xsi:type="array">
<!-- post-code field has custom UI component -->
<item name="component" xsi:type="string">Magento_Ui/js/form/element/post-code</item>
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="string">true</item>
</item>
</item>
It is located in the <item name="shipping-address-fieldset" xsi:type="array">
container.
To replace this element you will need your own module that will include a form update and a js element. This is the Vendor_Rules module in the example.
Create a file:
app/code/Vendor/Rules/view/frontend/requirejs-config.js`
var config = {
map: {
'*': {
"Magento_Ui/js/form/element/post-code": 'Vendor_Rules/js/form/element/post-code'
}
}
};
It should replace the default post-code element on the front-end.
app/code/Vendor/Rules/view/frontend/web/js/form/element/post-code.js
define([
'underscore',
'uiRegistry',
'Magento_Ui/js/form/element/abstract'
], function (_, registry, Abstract) {
'use strict';
return Abstract.extend({
defaults: {
imports: {
update: '${ $.parentName }.country_id:value'
}
},
/**
* @param {String} value
*/
update: function (value) {
var country = registry.get(this.parentName + '.' + 'country_id'),
options = country.indexedOptions,
option;
if (!value) {
return;
}
option = options[value];
this.error(false);
this.validation = _.omit(this.validation, 'required-entry');
this.required(false);
}
});
});
This is almost the exact copy of the default element, excluding a zip validation for countries where it is not optional. Ino other words, it is required from Magento point of view.
When done, run an update:
bin/magento setup:upgrade
bin/magento setup:static-content:deploy
Refresh a cache and check the result. It will look the following way in our case:
A new address form without required a zip code:
A new address saving without a zip code:
The last step at the Checkout:
And an error in the place order without a zip code:
As you can see, there is a validation of a zip code at the back-end. We should come over it.
A validation is located in the customer address model \Magento\Customer\Model\Address\AbstractAddress
, validate
method:
$_havingOptionalZip = $this->_directoryData->getCountriesWithOptionalZip();
if (!in_array(
$this->getCountryId(),
$_havingOptionalZip
) && !\Zend_Validate::is(
$this->getPostcode(),
'NotEmpty'
)
) {
$errors[] = __('Please enter the zip/postal code.');
}
The first solution is to add a zip code for all countries as optional. Let's check the getCountriesWithOptionalZip
method:
/**
* Return ISO2 country codes, which have optional Zip/Postal pre-configured
*
* @param bool $asJson
* @return array|string
*/
public function getCountriesWithOptionalZip($asJson = false)
{
if (null === $this->_optZipCountries) {
$value = trim(
$this->scopeConfig->getValue(
self::OPTIONAL_ZIP_COUNTRIES_CONFIG_PATH,
ScopeInterface::SCOPE_STORE
)
);
$this->_optZipCountries = preg_split('/\,/', $value, 0, PREG_SPLIT_NO_EMPTY);
}
if ($asJson) {
return $this->jsonHelper->jsonEncode($this->_optZipCountries);
}
return $this->_optZipCountries;
}
As you can see from the country code, the countries with the optional zip code are taken from the _optZipCountries
attribute that is filled in with data in the following way:
$this->scopeConfig->getValue(
self::OPTIONAL_ZIP_COUNTRIES_CONFIG_PATH,
ScopeInterface::SCOPE_STORE
)
Values are stored in the system settings general/country/optional_zip_countries
:
Finally, a simple solution:
You don't need to modify a code. You should only select all countries as countries with an optional zip code. After that a validation for them will be disabled!
Select all countries in the multiselect and save changes for the selected store. Then, disable our module and check the checkout:
A new address in the checkout:
The last step at the checkout:
An order placed has been placed successfully without a zip code:
Everything works correctly!
We provided the full research because it may help someone else.
UPDATE (11.01.16)
Sorry, we have misunderstood your question. Then, you need to use our first recommendation and slightly correct a code for the 'Magento_Ui/js/form/element/post-code.js' element. Perform the same actions, as described above but use the following code instead:
return Abstract.extend({
defaults: {
imports: {
update: '${ $.parentName }.country_id:value'
}
},
/**
* @param {String} value
*/
update: function (value) {
var country = registry.get(this.parentName + '.' + 'country_id'),
options = country.indexedOptions,
option;
if (!value) {
return;
}
option = options[value];
if (option['is_zipcode_optional']) {
this.error(false);
this.validation = _.omit(this.validation, 'required-entry');
} else {
this.validation['required-entry'] = true;
}
}
});
We removed the this.required(!option['is_zipcode_optional']);
line because it has activated the validation mechanism and caused the red frame to appear. Without this line everything should work smooth and the red frame won't appear.
-
Thanks for the elaborate answer. However, the 'required' system is working just fine. The only problem is that it highlights the postal code field when that checkout page loads. This is because in the previous step, you can already 'calculate shipping cost'. If you leave the field blank there and move on, the postal code field is the only field that highlights.. This looks weird. Is there a way to not 'trigger the requirement' on the load of this page?– CakeCommented Oct 31, 2016 at 13:32
-
-
I've added these 2 files with the code you provided but it doesn't solve the issue. I did need to create all these folders, they weren't there: (app/code/)Vendor/Rules/view/frontend/web/js/form/element/ I presume 'Vendor' is the vendor of the template right?– CakeCommented Nov 3, 2016 at 23:18
-
Alright so i got it to work but now the field doesn't get checked anymore at all. Even if I set required to true..– CakeCommented Nov 4, 2016 at 0:04
-
2@Cake It is possible, but we haven't tested the code at every step because we've tried to give you the right direction to solve your problem. Hope our solution has helped you.– MageworxCommented Nov 4, 2016 at 9:14
This error is caused by a magento2 core error.
Please have a look to this link : https://github.com/magento/magento2/issues/7724
data-validate="{required:true}"
? You can also change from Configuration magento.stackexchange.com/questions/19542/…