Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending jQuery UI widgets - override parent events?

I'm trying to extend the jQuery UI Autocomplete widget. In my custom widget, I need to be able to override the select event, while ideally also allowing the user of the widget to attach their own handler to that event as well.

Here's a jsfiddle of one of my attempts: http://jsfiddle.net/nN46R/

My first attempt (which is in the jsfiddle) was to bind to the event in _create:

$.widget("custom.myautocomplete", $.ui.autocomplete, {
    _create: function() {
        this._super("_create");

        // Doesn't work
        this.element.bind('autocompleteselect', function() {
            alert('Handling autocompleteselect!');
        });
    }
});

This didn't work. It will trigger if you change autocompleteselect to select, but only if you highlight any text within the textbox - but that's just jQuery's select handler firing, not jQuery UI's autocompleteselect. Not what I want.

Per this post, I tried defining a _select method within the widget:

$.widget("custom.myautocomplete", $.ui.autocomplete, {
    _create: function() {
        this._super("_create");
    },
    _select: function (event, ui) {
        alert('Handling select!');
    }
});

That also didn't work. I tried the same with just select (no underscore), but no luck.

The only thing that worked was to pass in a default handler using the options array, like so (jsfiddle):

$.widget("custom.myautocomplete", $.ui.autocomplete, {
    options: {
        select: function (event, ui) {
            alert('Handling select!');
        }
    }
});

But this has a couple problems. First, it doesn't look like it's possible to call any other methods in the custom widget from within the handler:

$.widget("custom.myautocomplete", $.ui.autocomplete, {
    options: {
        select: function (event, ui) {
            alert('Handling select!');

            // Doesn't work:
            // Uncaught TypeError: Object #<HTMLInputElement> has no method '_myCustomSelectHandler'
            this._myCustomSelectHandler();
        }
    },
    _myCustomSelectHandler: function (event, ui) {
        alert('In _myCustomSelectHandler!');
    }
});

Second, if the user defines their own select handler, then mine won't fire anymore:

$("#tags").myautocomplete({
    delay: 0,
    source: availableTags,
    select: function (e, ui) {
        alert("Muahaha! Me (the user) just overrode the select handler, and now yours won't get called!");
    }
});

So that doesn't really look like a solution.

So, is there any way I could extend the autocomplete widget and override the select handler?

like image 760
Sergey K Avatar asked Feb 06 '14 16:02

Sergey K


People also ask

How to extend jQuery widget?

We can extend jQuery widgets by using mixins. In java script mixin is a class whose methods are added to, or mixed in, with another class. In order to extend jQuery widget first we need to declare a mixin in requirejs-config.

What is a jQuery ui widget?

a jQuery UI widget is a specialized jQuery plug-in. Using plug-in, we can apply behaviours to the elements. However, plug-ins lack some built-in capabilities, such as a way to associate data with its elements, expose methods, merge options with defaults, and control the plug-in's lifetime.

What's a widget factory?

The widget factory defines how to create and destroy widgets, get and set options, invoke methods, and listen to events triggered by the widget. By using the widget factory to build your stateful plugins, you are automatically conforming to a defined standard, making it easier for new users to start using your plugins.


1 Answers

Figured it out! In the first code sample, all I had to do is bind to the myautocompleteselect event instead of autocompleteselect:

http://jsfiddle.net/nN46R/1/

$.widget("custom.myautocomplete", $.ui.autocomplete, {
    _create: function() {
        this._super("_create");

        // Works! Bind to the "myautocompleteselect" event, not
        // "autocompleteselect".
        this.element.bind('myautocompleteselect', function() {
            alert('Something selected!');
        });
    }
});

Apparently, the full name of the event that gets raised is the name of the widget concatenated with the name of the event (select). This is a custom widget, so you're supposed to use the custom widget's name, which in my example is myautocomplete.

As a side note, this is also relevant for the widget user if they want to bind to any events in their code, such as the autocomplete menu opening or closing. If this was the base autocomplete widget, they would bind to the menu opening event using:

$('#tags').bind('autocompleteopen', function(event, ui) {
    console.log('autocomplete menu opening');
});

However, if they're using the custom widget myautocomplete (which extends autocomplete), they would need to bind to the myautocompleteopen event instead:

$('#tags').bind('myautocompleteopen', function(event, ui) {
    console.log('custom autocomplete menu opening');
});

The event names of jQuery UI widget events are namespaced - important to keep in mind!

like image 192
Sergey K Avatar answered Oct 16 '22 23:10

Sergey K