admin管理员组

文章数量:1245031

I've been banging my head off my desk trying to get the jQuery UI Autoplete to output custom HTML. Here is my code.

        $(document).ready(function(){

        $.widget( "custom.catplete", $.ui.autoplete, {
            _renderMenu: function( ul, items ) {
                var self = this,
                    currentCategory = "";
                $.each( items, function( index, item ) {
                    if ( item.category != currentCategory ) {
                        ul.append( "<li class='ui-autoplete-category'>" + item.category + "<ul class='autoplete-category'></ul></li>" );
                        currentCategory = item.category;
                    }
                    self._renderItem( ul, item);
                });
            }
        });

        var data = [
            { label: "anders", category: "Antigen" },
            { label: "andreas", category: "Antigen" },
            { label: "antal", category: "Antigen" },
            { label: "annhhx10", category: "Products" },
            { label: "annk K12", category: "Products" },
            { label: "annttop C13", category: "Products" },
            { label: "anders andersson", category: "People" },
            { label: "andreas andersson", category: "People" },
            { label: "andreas johnson", category: "People" }
        ];

        $( "#typeAhead" ).catplete({
            delay: 0,
            source: data,
        })
        .data( "catplete" )._renderItem = function( ul, item ) {
            return $( "<li></li>" )
                .data( "item.catplete", item )
                .append( $( "<a class='ui-menu-item'></a>" ).text( item.label ) )
                .appendTo( $('ul').last('.autoplete-category'));
        };
    });

I seem to be running into trouble by nesting my lists in the renderItem function. The HTML output is exactly how I want it. However when I "keydown" the I get a javascript error (item is undefined).

Any ideas or suggestions? I've tried just about everything.

I've been banging my head off my desk trying to get the jQuery UI Autoplete to output custom HTML. Here is my code.

        $(document).ready(function(){

        $.widget( "custom.catplete", $.ui.autoplete, {
            _renderMenu: function( ul, items ) {
                var self = this,
                    currentCategory = "";
                $.each( items, function( index, item ) {
                    if ( item.category != currentCategory ) {
                        ul.append( "<li class='ui-autoplete-category'>" + item.category + "<ul class='autoplete-category'></ul></li>" );
                        currentCategory = item.category;
                    }
                    self._renderItem( ul, item);
                });
            }
        });

        var data = [
            { label: "anders", category: "Antigen" },
            { label: "andreas", category: "Antigen" },
            { label: "antal", category: "Antigen" },
            { label: "annhhx10", category: "Products" },
            { label: "annk K12", category: "Products" },
            { label: "annttop C13", category: "Products" },
            { label: "anders andersson", category: "People" },
            { label: "andreas andersson", category: "People" },
            { label: "andreas johnson", category: "People" }
        ];

        $( "#typeAhead" ).catplete({
            delay: 0,
            source: data,
        })
        .data( "catplete" )._renderItem = function( ul, item ) {
            return $( "<li></li>" )
                .data( "item.catplete", item )
                .append( $( "<a class='ui-menu-item'></a>" ).text( item.label ) )
                .appendTo( $('ul').last('.autoplete-category'));
        };
    });

I seem to be running into trouble by nesting my lists in the renderItem function. The HTML output is exactly how I want it. However when I "keydown" the I get a javascript error (item is undefined).

Any ideas or suggestions? I've tried just about everything.

Share Improve this question edited Aug 10, 2012 at 1:49 Andrew Whitaker 126k32 gold badges295 silver badges308 bronze badges asked Feb 5, 2011 at 17:03 NickNick 3571 gold badge4 silver badges12 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 12

You were almost there! I only made two changes to get this to work (Updated after ments from OP):

After digging into the jQueryUI autoplete source, it looks like the underlying menu that's used by the autoplete widget isn't too friendly toward nested elements.

I could be wrong about this, but I think the menu expects a simple <ul> with just children <li>s containing an anchor tag.

Edit: This line confirms my suspicion about the menu (found in jqueryUI 1.8.9's menu widget):

    var items = this.element.children("li:not(.ui-menu-item):has(a)")
        .addClass("ui-menu-item")
        .attr("role", "menuitem");

    items.children("a")
        .addClass("ui-corner-all")
        .attr("tabindex", -1)
        // mouseenter doesn't work with event delegation
        .mouseenter(function( event ) {
            self.activate( event, $(this).parent() );
        })
        .mouseleave(function() {
            self.deactivate();
        });

Basically, since your a tags were buried inside a nested list, they weren't getting recognized by the menu.

I bet you noticed in your original code that your autoplete menu items were not highlighting when you moused over them. This highlighting actually coincides with which menu item the widget thinks is active, which was causing your widget to fail when the user selected an item.

Since there's nothing semantically wrong or visually wrong with just giving the category lis a different class, I would restructure the widget's menu like this:

JavaScript:

_renderItem function:

.data( "catplete" )._renderItem = function( ul, item ) {
    return $( "<li></li>" )
        .data( "item.autoplete", item )
        .append( $( "<a class='ui-menu-item'></a>" )
                 .text( item.label ) )
        .appendTo(ul);
};

Your _renderMenu function:

_renderMenu: function( ul, items ) {
    var self = this,
        currentCategory = "";
    $.each( items, function( index, item ) {
        if ( item.category != currentCategory ) {
            ul.append( "<li class='ui-autoplete-category'>" + item.category + "</li>" );
            currentCategory = item.category;
        }
        self._renderItem( ul, item);
    });
}

Generated HTML for AutoComplete menu:

<ul class="ui-autoplete>
    <li class="ui-autoplete-category">Antigen</li>
    <li class="ui-menu-item" role="menuitem">
         <a class="ui-menu-item ui-corner-all" tabindex="-1">anders</a>
    </li>
    <li class="ui-menu-item" role="menuitem">
        <a class="ui-menu-item ui-corner-all" tabindex="-1">andreas</a>
    </li>
    <li class="ui-menu-item" role="menuitem">
        <a class="ui-menu-item ui-corner-all" tabindex="-1">antal</a>
    </li>
    <!-- More categories, items, etc.-->
</ul>

Judging by your ments, it seemed like you wanted the menu's HTML to be nested uls inside of lis for each category. Let me know if changing the HTML of the generated menu isn't an option for you for some reason.

I've updated the example: http://jsfiddle/andrewwhitaker/pjs7a/2/

Hope that helps.

本文标签: javascriptJquery UI Autocomplete Custom HTML (item is undefined)Stack Overflow