2

I would like to use JQuery.UI.Autocomplete component in my module for Magento 2. Also, I am using KO.js for the user interface of my application. So, I have added a custom binding for KO:

define([
'ko',
'jquery',
'jquery/ui'
], function (ko, $) {
'use strict';

ko.bindingHandlers.autoComplete = {

    init: function (element, valueAccessor) {
        var settings = valueAccessor();
        var selectedOption = settings.selected;
        var options = settings.options();
        var updateElementValueWithLabel = function (event, ui) {
            event.preventDefault();
            $(element).val(ui.item.label);
            if(typeof ui.item !== "undefined") {
                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);
            }
        });
    }
};
});

I've added the following code in my html template:

<div class="suggestions">
<input id="suggestion_box" type="text" data-bind="autoComplete: { selected: $data.productSuggestions.selectedSuggestion, options: $data.productSuggestions.suggestions }" />
</div>

It looks good, but it doesn't work. I've got a error message in the browser console. I debugged it and as it turned out, the reason of the issue is in the following lines(they start from the 6819 line) of jquery-ui.js library:

this.menu = $( "<ul>" )
            .addClass( "ui-autocomplete ui-front" )
            .appendTo( this._appendTo() )
            .menu({
                // disable ARIA support, the live region takes care of that
                role: null
            })
            .hide()
            .data( "ui-menu" );

The this.menu field is undefined, because of invoking data( "ui-menu" ) method. Methods that invoke before data() one are returns their results.

It seems like I've inited JQuery.UI.Autocomplete in a wrong way, but all examples of configuring are quite simple and I'm not sure what have I done wrong.

Any ideas?

2 Answers 2

14

jQuery ui menu extended in magento core library lib/web/mage/menu.js as mage.menu. jQuery generate widgetName for any component

name = name.split( "." )[ 1 ];
fullName = namespace + "-" + name;

Widget name used as attribute name for storage widget instance in widget DOM elements.

$.data( element, this.widgetName, this );

After extending by magento core widget name changed from ui-menu to mage-menu and element.data("ui-menu") become undefined.

Keep in mind that magento use different jquery-ui versions for frontend and backend and in one from this versions this issue reproduced (in frontend if I remember correctly)


You can use mixin as workaround for this issue

require-config.js

var config = {
    config: {
        mixins: {
            'mage/menu': {
                'Vendor_Module/js/lib/mage/menu-mixin': true
            }
        }
    }
};

Vendor_Module/view/frontend/web/js/lib/mage/menu-mixin.js

define([
    'jquery',
    'jquery/ui'
], function ($) {
    'use strict';

    return function (data) {

        $.widget('mage.menu', data.menu, {
            _create: function () {
                $(this.element).data('ui-menu', this);
                this._super();
            }
        });

        data.menu = $.mage.menu;

        return data;
    };
});
4
  • I have tried it. but still not working. Any idea?
    – vinothavn
    Jun 14, 2017 at 9:13
  • its not working Jan 29, 2018 at 14:40
  • 2 things need to be change for it to work from the above answer (At least for Magento 2.3.1). 1. File name require-config.js must be requirejs-config.js. 2. $.widget('mage.menu', data.menu, must be $.widget('mage.menu', $.ui.menu, {
    – Thanu
    Jul 25, 2019 at 1:11
  • You just saved my day! Thanks :) May 13, 2020 at 12:11
0

The small issue needs to be corrected in the above accepted answer

Please change

require-config.js to requirejs-config.js
1
  • @max You answer worked for me but you need to change require-config.js to requirejs-config.js Jan 2, 2019 at 2:46

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.