开发者

How to reference the top of the chain in jQuery for multiple formatted jQuery UI Autocomplete's on one page?

开发者 https://www.devze.com 2023-02-08 02:36 出处:网络
I\'m using the jQuery UI Autocomplete. It\'s great, but there\'s a problem with multiple autocomplete boxes on the same page with multiple monkey-patched solutions to format the results (currently yo

I'm using the jQuery UI Autocomplete.

It's great, but there's a problem with multiple autocomplete boxes on the same page with multiple monkey-patched solutions to format the results (currently you can only overwrite the original renderItem allowing one result format per page).

How to solve this problem is one of the great unsolved mysteries (as I can find) of the Autocomplete widget. I had the idea that if I can reference the id of the auto complete element I can add an if statement in the monkey patch allowing me to create multiple instances. Let me demonstrate:

The monkey patch to format results is:

$.ui.autocomplete.prototype._renderItem: function( ul, item) {
    return CUSTOMISE FORMATTING HERE;
};

If I specify on the same page, say:

$("#input1").autocomplete();

$("#input2").autocomplete();

I'm trying to achieve separate functions and had the idea of using the _RenderMenu:

$.ui.autoc开发者_JAVA百科omplete.prototype._renderMenu: function( ul, items ) {
    var self = this;
    $.each( items, function( index, item ) {
        self._renderItem( ul, item );
    });
};

by changing it to:

$.ui.autocomplete.prototype._renderMenu: function( ul, items ) {
    var self = this;
    $.each( items, function( index, item ) {
        if ( $$$$CLASS-OR-ID$$$$ == '#input1' ) {
             self._renderItemCustom1( ul, item );
        }
        else if ( $$$$CLASS-OR-ID$$$$ == '#input2' ) {
            self._renderItemCustom2( ul, item );
        }
        else {
            self._renderItem( ul, item );
        }
    });
};

This should enable the configuration of multiple configurations to format the auto complete results?

e.g. by configuring x number custom _renderItem functions, listed within _renderMenu:

$.ui.autocomplete.prototype._renderItemCustom1: function( ul, item) {
    return CUSTOMISE FORMATTING HERE;
};

So my question is, how can I reference the class or ID ($$$$CLASS-OR-ID$$$$ in the code) at the top of the chain within the _renderMenu function?

Hope this makes sense, thanks for your help!


OK, Solved it, thanks to a little inspiration from Karim, I decided it doesn't need to be the elementID, I just need to be able to specify different reference/option for each autocomplete which I achieved with the following:

$("#input1").autocomplete({
    source: source1,
    format: format1    /* This is my planted reference */
});
$("#input1").autocomplete({
    source: source2,
    format: format2
});

RenderMenu becomes:

$.ui.autocomplete.prototype._renderMenu: function( ul, items ) {
    var self = this;
    $.each( items, function( index, item ) {
        if ( this.options.format == 'format1' ) {
             self._renderItemCustom1( ul, item );
        }
        else if ( this.options.format == 'format2' ) {
            self._renderItemCustom2( ul, item );
        }
        else {
           self._renderItem( ul, item );
        }
    });
};

And I can specify infinite _RenderItem's like so as long as they are specified within _renderMenu:

$.ui.autocomplete.prototype._renderItemCustom1: function( ul, item ) {
    return CUSTOM FORMATTING;
}

It's also perhaps better than relying on element ID, as it means the same custom _renderItem can be used for multiple inputs with different IDs but the same output method.

EDIT: To make it a little more efficient and not bloat _renderMenu I recoded it:

$.ui.autocomplete.prototype._renderMenu = function( ul, items) {
    var self = this;
    if ( typeof this.options.format == 'undefined' ) {
        $.each( items, function( index, item ) {
            self._renderItem( ul, item );
        });
    }
    else {
        var fname = 'self._renderItem' + this.options.format + '( ul, item )';
        $.each( items, function( index, item ) {
            eval(fname);
        });
    }
}

This new code means you do not have to rewrite _renderMenu for each new _renderItem method, instead it will execute _renderItemFORMATNAME automatically if

format: FORMATNAME

is specified. Although for my original example

$.ui.autocomplete.prototype._renderItemCustom1
becomes:
$.ui.autocomplete.prototype._renderItemformat1


This might seem a bit hacky, but I honestly can't think of anything else. In short, we add a 'controlId' property to each data item. We override the _renderMenu method to read this property, and run its value through some conditions:

$.ui.autocomplete.prototype._renderMenu = function(ul, items) {
    var self = this;
    $.each(items, function(index, item) {
        if (item.controlId == 'foo') {
            alert('got foo');
            self._renderItemCustom1(ul, item);
        }
        else if (item.controlId == 'bar') {
            alert('got bar');
            self._renderItemCustom2(ul, item);
        }
        else {
            self._renderItem(ul, item);
        }
    });
};

// each object should have a 'controlId' parameter
var projects = [
    {
    value: "jquery",
    label: "jQuery",
    desc: "the write less, do more, JavaScript library",
    icon: "jquery_32x32.png",
    controlId: 'foo'}, // this tells the AC which
{
    value: "jquery-ui",
    label: "jQuery UI",
    desc: "the official user interface library for jQuery",
    icon: "jqueryui_32x32.png",
    controlId: 'foo'},
{
    value: "sizzlejs",
    label: "Sizzle JS",
    desc: "a pure-JavaScript CSS selector engine",
    icon: "sizzlejs_32x32.png",
    controlId: 'foo'}
];

$("#foo").autocomplete({
    source: projects
});

I honestly hope someone posts a prettier solution than this one. Anyway, here is a demonstration.

0

精彩评论

暂无评论...
验证码 换一张
取 消