官术网_书友最值得收藏!

Custom data and categories

One approach to separating two categories of autocomplete data might be to have two distinct fields, each with their own autocomplete widgets. Another would be to introduce the notion of a category into the widget itself. When the drop-down menu appears to suggest items for the user, they will also see the category the item belongs to. To do this in the autocomplete widget, we need to change both how the widget understands the source data, and how the menu items are rendered.

How to do it...

We're going to extend the autocomplete widget in order to change how the menu items are rendered. We also need to consider the data passed into the widget as the source.

( function( $, undefined ) {

$.widget( "ab.autocomplete", $.ui.autocomplete, {

    _renderMenu: function( ul, items ) {

        var that = this,
            currentCategory = "";

        items.sort(function( a, b ) {
            return a.cat > b.cat 
        });

        $.each( items, function( index, item ) {

            if ( item.cat != currentCategory ) {
                that._renderCategory( ul, item );
                currentCategory = item.cat;
            }

            that._renderItemData( ul, item );

        });

    },

    _renderCategory: function( ul, item ) {
        return $( "<li>" ).addClass( "ui-autocomplete-category" )
                          .html( item.cat )                          
                          .appendTo( ul );
    },

    _renderItem: function( ul, item ) {
        return $( "<li>" ).addClass( "ui-autocomplete-item" )
                          .append( $( "<a>" )
                          .append( $( "<span>" ).html( item.label ) )
                          .append( $( "<span>" ).html( item.desc ) ) )
                          .appendTo( ul );
    }

});

})( jQuery );

$( function() {

    var items = [
        {
            value: "First Item",
            label: "First Item",
            desc: "A description of the first item goes here",
            cat: "Completed"
        },
        {
            value: "Second Item",
            label: "Second Item",
            desc: "A description of the second item goes here",
            cat: "In Progress"
        },
        {
            value: "Third Item",
            label: "Third Item",
            desc: "A description of the third item goes here",
            cat: "Completed"
        }
    ];

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

});

We're almost done. The changes we've made to the menu will not just magically work out, we need to apply some styles. The following CSS code should be included on the page:

.ui-autocomplete-category {
    font-weight: bold;
    padding: .2em .4em;
    margin: .8em 0 .2em;
    line-height: 1.5;
}

.ui-autocomplete-item > a > span {
    display: block;
}

.ui-autocomplete-item > a > span + span {
    font-size: .9em;
}

Now, if you start typing in the autocomplete, you'll notice a drop-down menu drastically different from what we're used to as it contains both category and description information.

How it works...

The goal of this widget extension is to accept custom source data and to use that data in the display of the drop-down menu. Specifically, the new data we're working with is the category and the description. The category is a one-to-many relationship with the items insofar, as several items we pass to the widget may have the same category string. Our job is to figure out which items fall under any given category and to represent this structure in the drop-down menu. Additionally, the description of the item is a one-to-one relationship, so less work is required here but we nonetheless would like to include the description in the drop-down menu.

The first method from the original implementation that we're overriding is _renderMenu(). The job of _renderMenu() is to alter the underlying HTML structure each time a suggestion is made to the user. We keep track of the current category with currentCategory. We then render each item with _renderItem().

The _renderCategory() function renders the category text as an <li>. It also adds the ui-autocomplete-category class. Likewise, our _renderItem() function renders the item text, and it is here that we also make use of the desc attribute. The item also has the ui-autocomplete-item class.

The new CSS styles we've included in our UI are a necessary component of the new version of autocomplete that we've created. Without them, the description would be of the same font size and would display on the same line as the item label. Likewise, the category needs the newly-added styles to stand out as a category that groups other items instead of just another item.

There's more...

Whenever we extend the data used by the autocomplete widget, we have to tell the widget how to work with it. Here, we've told autocomplete how to display the new data in the drop-down menu. Alternatively, we could tell the widget to perform filtering on some data fields that the user never actually sees in the drop down-menu. Or we could combine the two.

Here is how we would go about using both the category and the description, both non-standard fields, in the filtering when the user starts typing.

$.ui.autocomplete.filter = function( array, term ) {

    var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );

    return $.grep( array, function( value ) {
        return matcher.test( value.cat ) || 
               matcher.test( value.desc ) ||
               matcher.test( value.label )
    });

};

Here we're replacing the filter() function that autocomplete uses with our own implementation. The two are similar, we're just adapting the RegExp.test() calls to the desc and cat field. We would place this code just beneath the custom widget declaration of autocomplete. The reason this is done externally to the customization specification is because autocomplete.filter() is kind of like a static method. Where with other methods, we're overriding on a per-instance basis.

主站蜘蛛池模板: 平乡县| 武隆县| 灌云县| 利辛县| 军事| 改则县| 泗水县| 常州市| 深泽县| 荃湾区| 中卫市| 杭锦后旗| 左权县| 连城县| 平塘县| 大石桥市| 乌什县| 沾化县| 马公市| 寻乌县| 澜沧| 东安县| 吴江市| 农安县| 什邡市| 木里| 武胜县| 安泽县| 高密市| 江油市| 湟中县| 赤城县| 嘉兴市| 中阳县| 温泉县| 双柏县| 广灵县| 枞阳县| 蒙城县| 徐州市| 津南区|