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?

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

| improve this answer | |
  • Didn't work either – Gabriela Oct 8 '18 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"/>
| improve this answer | |
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"/> 
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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