2

The Context:

I'm implementing an autocomplete functionality in checkout page and i've added two inputs (ccity and ccity_id). I need ccity_id to be hidden while storing the value of the selected label in ccity.

The Problem:

The Component (.js) is loaded, as well as the templates but the console.log() message is not getting printed and the autocomplete is not getting called either. There are no errors at all (i mean, complainings about bindings or undefined elements, etc). So, the custom binding is not getting initialize.

What I've Done:

I have created two custom inputs (with custom component and template). For ccity and ccity_id the Component is the same but the HTML Templates are not.

In Vendor/Module/view/frontend/layout/checkout_index_index is the definition of the inputs.

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="checkout" 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">
                                                            <item name="shipping-address-fieldset" xsi:type="array">
                                                                <item name="children" xsi:type="array">
                                                                    <item name="ccity" xsi:type="array">
                                                                        <item name="component" xsi:type="string">Vendor_Module/js/autocomplete</item>
                                                                        <item name="template" xsi:type="string">ui/form/field</item>
                                                                        <item name="config" xsi:type="array">
                                                                            <!-- customScope is used to group elements within a single form (e.g. they can be validated separately) -->
                                                                            <item name="customScope" xsi:type="string">shippingAddress</item>
                                                                        </item>
                                                                        <item name="provider" xsi:type="string">checkoutProvider</item>
                                                                        <item name="dataScope" xsi:type="string">shippingAddress.ccity</item>
                                                                        <item name="label" xsi:type="string">City</item>
                                                                        <item name="sortOrder" xsi:type="string">100</item>
                                                                    </item>
                                                                    <item name="ccity_id" xsi:type="array">
                                                                        <item name="component" xsi:type="string">Vendor_Module/js/autocomplete</item>
                                                                        <item name="template" xsi:type="string">ui/form/field</item>
                                                                        <item name="config" xsi:type="array">
                                                                            <!-- customScope is used to group elements within a single form (e.g. they can be validated separately) -->
                                                                            <item name="customScope" xsi:type="string">shippingAddress</item>
                                                                            <item name="elementTmpl" xsi:type="string">Vendor_Module/autocomplete/customhidden</item>
                                                                        </item>
                                                                        <item name="provider" xsi:type="string">checkoutProvider</item>
                                                                        <item name="dataScope" xsi:type="string">shippingAddress.ccity_id</item>
                                                                        <item name="label" xsi:type="string">City_Id</item>
                                                                        <item name="sortOrder" xsi:type="string">101</item>
                                                                    </item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>                                            
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </argument>
                </arguments>
        </referenceBlock>
    </body>
</page>

In Vendor/Module/web/js/autocomplete.js i've defined the component.

define([
    'Magento_Ui/js/form/element/abstract',
    'mage/url',
    'ko',
    'jquery',
    'jquery/ui'
], function (Abstract, url, ko, $) {
    'use strict';

    ko.bindingHandlers.autoComplete = {

        init: function (element, valueAccessor) {

            console.log("Init - Custom Binding");
            console.log(element);
            console.log(valueAccessor);

            // valueAccessor = { selected: mySelectedOptionObservable, options: myArrayOfLabelValuePairs }
            var settings = valueAccessor();

            var selectedOption = settings.selected;
            var options = settings.options;

            var updateElementValueWithLabel = function (event, ui) {
                // Stop the default behavior
                event.preventDefault();

                // Update the value of the html element with the label
                // of the activated option in the list (ui.item)
                $(element).val(ui.item.label);

                // Update our SelectedOption observable
                if(typeof ui.item !== "undefined") {
                    // ui.item - id|label|...
                    selectedOption(ui.item);
                }
            };

            $(element).autocomplete({
                source: options,
                select: function (event, ui) {
                    updateElementValueWithLabel(event, ui);
                },
                focus: function (event, ui) {
                    updateElementValueWithLabel(event, ui);
                },
                change: function (event, ui) {
                    updateElementValueWithLabel(event, ui);
                }
            });

        }
    };

    return Abstract.extend({
        defaults: {
            elementTmpl: 'Vendor_Module/autocomplete/custominput'
        },
        selectedOption: ko.observable(''),
        getElements: function( request, response ) {
            var departmentValue = $('anotherInput').val();
            $.ajax({
                url: url.build('list/check/cities/'),
                data: {
                    q: request.term,
                    filter: departmentValue
                },
                contentType: "application/json",
                type: "POST",
                dataType: 'json',
                error : function () {
                    alert("An error have occurred.");
                },
                success : function (data) {
                    // Data is of the form: [{"city_id": "some_id", "city": "some_city"}, ...]
                    response( data );
                }
            });
        },
        selectedValue: ko.observable('')
    });
});

In the above i've defined my custom binding and i've extended the Abstract component with my custom template for ccity which is defined in Vendor/Module/view/frontend/web/template/autocomplete/custominput.html as follows:

<div class="autocomplete">
    <input id="custom_input" type="text" data-bind="autocomplete: { selected: selectedOption, options: options } " />
</div>

In Vendor/Module/view/frontend/web/template/autocomplete/customhidden.html i've defined the template for ccity_id as follows:

<input class="admin__control-text" type="hidden"
       data-bind="
        value: selectedValue,
        hasFocus: focused,
        attr: {
            name: inputName,
            placeholder: placeholder,
            'aria-describedby': noticeId,
            id: uid
    }"/>

What could i be missing?

PS: As a basis i'm using the post in http://cameron-verhelst.be/blog/2014/04/20/knockoutjs-autocomplete/

Thanks,

2 Answers 2

0

Take a look at this post. This should give you an idea what you're doing wrong. You can read about Magento 2 jQuery-ui styles in the Magento 2 doc.

3
  • Thank you for your reply. I have looked at the post you linked but it there's no error in the jquery-ui.js with or without the mixin. I've corrected my code with a few errors i had and i've updated my answer to explain some new errors. Thanks again.
    – A. Martz
    Feb 13, 2017 at 17:18
  • About your problem of validation error. I suggest you to ask again in new post specifically about that and edit that part out of this post. The main reason is that this post is hard to follow, because it is quite long and title does not specify(explain) what is the problem. Feb 13, 2017 at 22:01
  • I have posted a new question regarding the validation error and rolled back the edit (and answered) on this one to provide clarity. I'll look into the Magento 2 doc you suggested. Thank you so much.
    – A. Martz
    Feb 14, 2017 at 15:30
0

I've managed to almost make it work, almost. I have some new problems that i haven't been able to resolve yet but following the recommendation of another user, i'll remove the edit and post a new question with the new specific problems. This is the link for the newly created post: Validation Error with jQuery-UI Autocomplete and KnockoutJs - Magento 2 i posted there the code with the corrections i made so the Component started working.

The main reason by which the binding wasn't working before consisted in a typo. In the Js Component i had "ko.bindingHandlers.autoComplete" but in the templates i had: data-bind="autocomplete: { selected: selectedOption, options: options }". There was another problem with the way the autocomplete method call was returning the array to be shown.

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.