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?

4
  • When you use component there is no need to applyBindings on it.It will do it automatically 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
    – Gabriela
    Apr 13, 2018 at 14:54
  • @Gabriela, Have you got any solution for this? Jun 22, 2018 at 9:48
  • Sorry, I didn't find a solution. If you have any, please post it here.
    – Gabriela
    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

1
  • Didn't work either
    – Gabriela
    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"/>
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"/> 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.