4

I'm using jQuery UI Autocomplete with a categorized search result and I want to spice it up with CSS.

Unfortunately, jQuery UI doesn't make it easy and the default markup is really difficult to work with:

<input class="ui-autocomplete-input"/>
<ul class="ui-autocomplete ui-menu ui-widget ui-widget-content ui-corner-all">
  <li class='ui-autocomplete-category'>Category 1</li>
  <li class="ui-menu-item">
      <a class="ui-corner-all">item 1</a>
  </li>
  <li class="ui-menu-item">
      <a class="ui-corner-all">item 2</a>
  </li>
  <li class="ui-menu-item">
      <a class="ui-corner-all">item 3</a>
  </li>
  <li class='ui-autocomplete-category'>Category 2</li>
  <li class="ui-menu-item">
      <a class="ui-corner-all">item 1</a>
  </li>
  <li class="ui-menu-item">
      <a class="ui-corner-all">item 2</a>
  </li>
  <li class="ui-menu-item">
      <a class="ui-corner-all">item 3</a>
  </li>    
</ul>

The markup that I want is this:

<input class="ui-autocomplete-input"/>
<ul class="ui-autocomplete ui-catcomplete">
    <div class="ui-block">
        <div class="ui-autocomplete-category">Category 1</div>
        <div class="ui-list">
            <li class="ui-menu-item">
                <a class="ui-corner-all">item 1</a>
            </li>
            <li class="ui-menu-item">
                <a class="ui-corner-all">item 2</a>
            </li>
            <li class="ui-menu-item">
                <a class="ui-corner-all">item 3</a>
            </li>
        </div>
    </div>
    <div class="ui-block">
        <div class="ui-autocomplete-category">Category 1</div>
        <div class="ui-list">
            <li class="ui-menu-item">
                <a class="ui-corner-all">item 1</a>
            </li>
            <li class="ui-menu-item">
                <a class="ui-corner-all">item 2</a>
            </li>
            <li class="ui-menu-item">
                <a class="ui-corner-all">item 3</a>
            </li>
        </div>
    </div>
</ul>

And that's where I reach my limit.

I actually managed to create the markup, but I could no longer select and submit by clicking on the item.

Here is the code I came up with:

$.widget( "custom.catcomplete", $.ui.autocomplete, {

    _renderMenu: function( ul, items ) {
        var self = this,
            currentCategory = "",
            i = 0;

        $.each( items, function( index, item ) {
            if ( item.category != currentCategory ) {

                ul.append( "<div class='ui-autocomplete-category'>" + item.category + "</div>");
                currentCategory = item.category;

            }

            self._renderItem( ul, item );
        });

        /* This is how I thought it would work */

        ul.find('.ui-autocomplete-category').each(function() {
            $(this).nextUntil('div')
                    .andSelf()
                    .wrapAll('<div class="ui-block">')
                    .nextUntil('div')
                    .wrapAll('<div class="ui-list">');
        });

    },

    _renderItem: function( ul, item) {
        return $( "<li></li>" )
        .data( "item.autocomplete", item )
        .append( "<a>" + item.label + "</a>" )
        .appendTo( ul );
    },
});

$(function() {  
    $( "#ui-autocomplete-input" ).catcomplete({
        source: '<?php echo SITEURL?>/users/complete/',
        delay: 0,
        autoFocus: true,
        select: function(event, ui) {
            if(ui.item)
            {
                $('#ui-autocomplete-input').attr('value',ui.item.value);
            }
            $('#ui-autocomplete-form').submit();
        }
    });
});

So basically, the select: function part doesn't work at all.

Could anyone help me with this?

I'm sure there is a simpler way to modify the default markup and make it work just fine.

This is what I want it to look like:

Screenshot of drop-down list with multiple rows and header on left

3
  • 2
    A div is not a valid child element of an unordered list so you're already asking for rendering problems. Could you describe your intent when it comes to styling these elements? Commented Dec 19, 2011 at 21:12
  • whatever, I can use a <span> and display it as a block, it doesn't change anything style-wise. I want to float the category on the left and put the items on the right, thus saving some space Commented Dec 19, 2011 at 21:24
  • dl.dropbox.com/u/22030683/autocomplete.png Commented Dec 19, 2011 at 21:30

2 Answers 2

4

I eventually found the solution by myself and it involves some CSS trickery and some simple jQuery.

CSS:

.ui-autocomplete {
    width:424px;
    margin:0;
    padding:0 0 14px 0;
}

.ui-autocomplete-category {
    width:100px;
    position: absolute;
    padding:0 20px;
    margin:20px 0 0 0;
}

.ui-menu-item {
    padding-left:140px;
}

.ui-first {
    padding-top:20px;
}

jQuery:

$( "#search" ).catcomplete({
    delay: 0,
    source: data,
    autoFocus: true,
    select: function(event, ui) {
        if(ui.item) { $('#search').attr('value',ui.item.value);}
        $('#form').submit();
        },

    /* This is the important part! */

    open: function() {
        $('.ui-autocomplete-category').next('.ui-menu-item').addClass('ui-first');
    }    
});

Basically, I play with absolute positioning for putting the category name on the left and I add a class to the first LI element with jQuery in order to create some spacing with PADDING.

It's not perfect but it works flawlessly :)

Sign up to request clarification or add additional context in comments.

2 Comments

Congrats on the solution. When you are able, please mark your answer as 'accepted' by clicking the checkmark to the left. This will let others learn from your success. Cheers~
i followed the solution you mentioned exactly the same, but it doesn't work for me at all. especially, the code that wraps div around the li.
1

You could solve this without changing the HTML with a little bit of CSS trickery:

ul.ui-autocomplete {
    padding-left: 200px;
}

    ul.ui-autocomplete li.ui-autocomplete-category {
        width: 200px;
        height: 50px;
        margin-left: -200px;
        margin-bottom: -50px;
    }

It's not perfect (the height of the category li might exceed the height of the results - OR it might not fit the contents of the li) but it works.

Btw: the only valid child element of a ul is a li. So span wouldn't help you either.

2 Comments

You are absolutely right about the unordered list, I don't know what I was thinking, perhaps I don't really care when it comes to putting SPANS and DIVS wherever I want them to be.
Anyway, I found another solution some time later that day and it's similar to yours because it doesn't change the markup and uses some CSS trickery as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.