Magento – Magento 2 checkout knockout.js in custom template error – telephone field

checkoutjavascriptknockoutjsmagento2

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?

Best Answer

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

Related Topic