1

I'm trying to create a mask for telephone field in Magento 2.2.2 checkout. In order to do so. I placed a checkout_index_index.xml with a new template for telephone field at

vendor/mytheme/Magento_Checkout/layout/checkout_index_index.xml

 <?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
 <body>
 <referenceBlock name="checkout.root">
 <arguments>
 <argument name="jsLayout" xsi:type="array">
 <item name="components" xsi:type="array">
 <item name="checkout" xsi:type="array">
 <item name="children" xsi:type="array">
 <item name="steps" xsi:type="array">
 <item name="children" xsi:type="array">
 <item name="shipping-step" xsi:type="array">
 <item name="children" xsi:type="array">
 <item name="shippingAddress" xsi:type="array">
 <item name="children" xsi:type="array">
 <!-- The name of the form the field belongs to -->
 <item name="shipping-address-fieldset" xsi:type="array">
 <item name="children" xsi:type="array">
 <!-- the field you are customizing -->
 <item name="telephone" xsi:type="array">
 <item name="component" xsi:type="string">Magento_Checkout/js/view/masked</item>
 <item name="config" xsi:type="array">
 <!-- Assigning a new template -->
 <item name="elementTmpl" xsi:type="string">Magento_Checkout/form/element/telefone</item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </argument>
 </arguments>
 </referenceBlock>
 </body>
</page>

In the folder vendor/mytheme/web/js/view/masked.js I place bellow code

define(['jquery', 'uiComponent', 'ko', ], function ( ,ドル Component, ko) {
 'use strict';
 return Component.extend({
 defaults: {
 template: 'Magento_Checkout/telefone'
 },
 initialize: function () {
 var self = this;
 this._super();
 ko.bindingHandlers.maskedInput = {
 init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
 ko.bindingHandlers.value.init(element, valueAccessor, allBindings, viewModel, bindingContext);
 },
 update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
 ko.bindingHandlers.value.update(element, valueAccessor, allBindings, viewModel, bindingContext);
 $(element).mask(allBindings.get('mask'));
 valueAccessor()($(element).val());
 }
 };
 var ViewModel = function() {
 this.phone = ko.observable("");
 this.phone('123123451212');
 }; 
 ko.applyBindings(new ViewModel());
 }
 } 
)
}
);

And the I created template telefone.html at vendor/mytheme/Magento_Checkout/web/template

<input class="input-text" type="text" data-bind="
 value: value,
 valueUpdate: 'keyup',
 maskedInput: phone, 
 mask: '(999) 999-9999',
 hasFocus: focused,
 attr: {
 name: inputName,
 placeholder: placeholder,
 'aria-describedby': noticeId,
 id: uid,
 disabled: disabled
 }" />

But when I go to checkout I get error: Uncaught Error: You cannot apply bindings multiple times to the same element. Does someone know a proper way to apply phone mask to telephone input at checkout. Or, if my method is correct, what am I missing or doing wrong?

7ochem
7,61516 gold badges54 silver badges82 bronze badges
asked Apr 13, 2018 at 13:50
4
  • When you use component there is no need to applyBindings on it.It will do it automatically Commented Apr 13, 2018 at 14:04
  • I removed " ko.applyBindings(new ViewModel());" and now I get ReferenceError: Unable to process binding "css: function (){return additionalClasses }" Message: Can't find variable: additionalClasses Commented Apr 13, 2018 at 14:54
  • @Gabriela, Have you got any solution for this? Commented Jun 22, 2018 at 9:48
  • Sorry, I didn't find a solution. If you have any, please post it here. Commented Jun 29, 2018 at 13:05

3 Answers 3

1

There is seems to be a conflict because below layout you have already mentioned the template of element and re-defined the template in your component js file also,

vendor/mytheme/Magento_Checkout/layout/checkout_index_index.xml

<!-- the field you are customizing -->
<item name="telephone" xsi:type="array">
 <item name="component" xsi:type="string">Magento_Checkout/js/view/masked</item>
 <item name="config" xsi:type="array">
 <!-- Assigning a new template -->
 <item name="elementTmpl" xsi:type="string">Magento_Checkout/form/element/telefone</item>
 </item>
</item>

Hence try replace below component script with your, vendor/mytheme/web/js/view/masked.js

define([
 'underscore', 'ko',
 'mageUtils', 
 'Magento_Ui/js/form/element/abstract',
 'uiLayout'
], function (_, ko, utils, Abstract, layout) {
 'use strict';
 return Abstract.extend({
 initialize: function () {
 this._super();
 //add your custom code or call custom functions
 ko.bindingHandlers.maskedInput = {
 init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
 ko.bindingHandlers.value.init(element, valueAccessor, allBindings, viewModel, bindingContext);
 },
 update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
 ko.bindingHandlers.value.update(element, valueAccessor, allBindings, viewModel, bindingContext);
 $(element).mask(allBindings.get('mask'));
 valueAccessor()($(element).val());
 }
 };
 var ViewModel = function() {
 this.phone = ko.observable("");
 this.phone('123123451212');
 }; 
 ko.applyBindings(new ViewModel());
 return this;
 } 
 });
});

Note : script extends from Magento_Ui/js/form/element/abstract

answered Aug 29, 2018 at 6:49
1
  • Didn't work either Commented Oct 8, 2018 at 17:23
1

My goal is just to put a mask for the telephone field in Magento2 Checkout. Since the Knockout method didn't work I simple declared a new template in checkout_index_index.xml with the bellow code:

 <input class="input-text" type="text" placeholder= (__)_____-____ data-bind="
 value: value,
 valueUpdate: 'keyup',
 attr: {
 name: inputName, 
 id: uid
 }" name="telephone" aria-required="true" aria-invalid="false" autocomplete="off" onfocus="this.value='(';" onkeyup="var telephone = this.value; 
 if (telephone.match(/^\(\d{2}$/) !==null) {
 this.value = telephone + ')';
 } else if (telephone.match(/^\(\d{2}\)\d{5}$/) !== null) {
 this.value = telephone + '-';
 }" maxlength="14"/>
answered Dec 9, 2018 at 1:47
1

Ok, I finally found a better way to do it. I used

https://igorescobar.github.io/jQuery-Mask-Plugin/

Then I create a module in which I create a requirejs-config.js in /vendor/module/view/frontend/requirejs-config.js with following code

var config = {
 map: {
 '*': {
 mask: 'BeeVirtual_Telephone/js/mask' //this the js found in igorescobar github repository
 }
 }
}

So place mask.js at /vendor/module/view/frontend/web/js

Then in checkout_index_index.xml declare your new telephone.html file

 <?xml version="1.0"?>
 <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
 <body>
 <referenceBlock name="checkout.root">
 <arguments>
 <argument name="jsLayout" xsi:type="array">
 <item name="components" xsi:type="array">
 <item name="checkout" xsi:type="array">
 <item name="children" xsi:type="array">
 <item name="steps" xsi:type="array">
 <item name="children" xsi:type="array">
 <item name="shipping-step" xsi:type="array">
 <item name="children" xsi:type="array">
 <item name="shippingAddress" xsi:type="array">
 <item name="children" xsi:type="array">
 <!-- The name of the form the field belongs to -->
 <item name="shipping-address-fieldset" xsi:type="array">
 <item name="children" xsi:type="array">
 <!-- the field you are customizing -->
 <item name="telephone" xsi:type="array">
 <item name="component" xsi:type="string">Vendor_Module/js/view/masked</item>
 <item name="config" xsi:type="array">
 <!-- Assigning a new template -->
 <item name="elementTmpl" xsi:type="string">Magento_Checkout/form/element/telefone</item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </item>
 </argument>
 </arguments>
 </referenceBlock>
 </body>
 </page>

Then in my masked.js file

define(
 [
 'underscore',
 'ko',
 'mage/url',
 'jquery',
 'mask',
 ],
 function (_, ko, Component, urlBuilder, jQuery, mask) {
 'use strict';
 ko.bindingHandlers.mask = {
 init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
 var mask = valueAccessor();
 jQuery(element).mask(mask);
 }
 };
});

Then in telephone.html

<input class="input-text" type="text" placeholder= (__)_____-____ data-bind="
 value: value,
 valueUpdate: 'keyup',
 attr: {
 'aria-describedby': getDescriptionId(),
 'aria-invalid': error() ? true : 'false', 
 name: inputName, 
 id: uid,
 mask:'(00)00000-0000'
 }" name="telephone" aria-required="true" aria-invalid="" autocomplete="off" maxlength="14"/> 
answered Nov 17, 2019 at 2:31

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.