Thursday, April 24, 2014

jQuery UI: Autocomplete With Select Elements

The jQuery UI autocomplete widget expects an input as it's target element. It also expects a data source — the fundamental job of the autocomplete widget is tying these two things together. When the user starts typing, the autocomplete filters the data source, and offers the user a selection of possible input text values. When you think about it, the select element is similar to the autocomplete.

The select element is in use everywhere, and it's an easy way for users to make quick selections given a small set of options. It has to be a small number of options, otherwise, you've offered no real benefit to the user — they have to scroll through a list.

For cases where the size of the select options has grown out of control to the point where your users are threatening you daily, you can use the autocomplete widget instead. Just simply extend the widget, as this example illustrates, and you can target select elements now, without the need for specifying a data source option. Here's how the extension works.

_create: function() {
    
    if ( this.element.is( "select" ) ) {
        
        var self = this;
        this.original = this.element.hide();
        this.element = $( "<input/>" )
            .insertAfter( this.original );

        this.options.source = function( request, response ) {
            var filter = $.ui.autocomplete.filter,
                $options = self.original.find( "option" ),
                result = $options.map( function() {
                    return $( this ).val();
                });
            response( filter( result, request.term ) );
        };

    }

    this._super( "_create" );

}

This is the new constructor we're supplying to autocomplete in our widget extension. If the target element isn't a select, then we pass control back to the original implementation and do nothing. On the other hand, if we did get a select element as the target, then we have to hide it and display a text input instead. It's an autocomplete, so users need a means to type what they're after. The select element gets stored in the original property so that we can restore it later on, when we're done with the widget.

Now that the text input is created and ready for use, we need the data source. This is actually quite easy — we just map the select option values into an array, and pass that to the default autocomplete filtering facilities.

And that's all the interesting stuff — the destructor in our autocomplete extension just removes the input element we inserted into the DOM and restores the original select element.