Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery UI Autocomplete v1.8.14 Multi-word Search + Highlighting

I'm trying to achieve two things using jQuery UI Autocomplete v1.8.14.

1) Use a space delimited word search for all matches (independent of order): (eg search "some heart", matches "win the heart of someone")

2) Highlight all of the matches: (eg search "some heart", matches "win the heart of some one")

This question has been asked multiple times, but I have been unable to find simple, reproducible code showing correct implementation.

I've started a JS Fiddle: http://jsfiddle.net/KywMH/2/. If possible please answer in the form of reproducible code.

Thank you.

like image 597
jmm Avatar asked Aug 21 '11 17:08

jmm


3 Answers

Here's one way: See it in action at jsFiddle.

var availableTags = [
    "win the day",
    "win the heart of",
    "win the heart of someone"
];
var autoCompNodeId  = 'tags';

$( "#" + autoCompNodeId ).autocomplete ( {
    source: function (requestObj, responseFunc) {
                var matchArry   = availableTags.slice (); //-- Copy the array
                var srchTerms   = $.trim (requestObj.term).split (/\s+/);

                //--- For each search term, remove non-matches.
                $.each (srchTerms, function (J, term) {
                    var regX    = new RegExp (term, "i");
                    matchArry   = $.map (matchArry, function (item) {
                        return regX.test (item)  ?  item  : null;
                    } );
                } );

                //--- Return the match results.
                responseFunc (matchArry);
            },

    open:   function (event, ui) {
                /*--- This function provides no hooks to the results list, so we have to trust the
                    selector, for now.
                */
                var resultsList = $("ul.ui-autocomplete > li.ui-menu-item > a");
                var srchTerm    = $.trim ( $("#" + autoCompNodeId).val () ).split (/\s+/).join ('|');

                //--- Loop through the results list and highlight the terms.
                resultsList.each ( function () {
                    var jThis   = $(this);
                    var regX    = new RegExp ('(' + srchTerm + ')', "ig");
                    var oldTxt  = jThis.text ();

                    jThis.html (oldTxt.replace (regX, '<span class="srchHilite">$1</span>') );
                } );
            }
} );


Because the old highlight function is no longer available, we use the open event to highlight the search terms. Pay special attention not to highlight inside tags.

like image 124
Brock Adams Avatar answered Oct 21 '22 00:10

Brock Adams


The solution below solves these two problems by

1) Modifying the autocomplete source function

2) Modifying .data('autocomplete')._renderItem

A working JS Fiddle can be found here: http://jsfiddle.net/W8MKt/7/

Any critique of the code or the solution would be appreciated.

Thank you.

<div class="ui-widget">
<label for="tags">Multi-word search: </label>
<input id="tags">
</div>

$(function() {
    var availableTags = [
        "win the day",
        "win the heart of",
        "win the heart of someone"
    ];

    $( "#tags" ).autocomplete({
        source: function(request, response) {

            var aryResponse = [];
            var arySplitRequest = request.term.split(" ");

            for( i = 0; i < availableTags.length; i++ ) {

                var intCount = 0;
                for( j = 0; j < arySplitRequest.length; j++ ) {

                    regexp = new RegExp(arySplitRequest[j]);

                    var test = availableTags[i].match(regexp);

                    if( test ) {

                        intCount++;

                    } else if( !test ) {

                    intCount = arySplitRequest.length + 1;

                    }

                    if ( intCount == arySplitRequest.length ) {

                        aryResponse.push( availableTags[i] );

                    }
                };
            }

            response(aryResponse);

        }

    }).data('autocomplete')._renderItem = function( ul, item ) {

        var srchTerm = $.trim(this.term).split(/\s+/).join ('|');

        var strNewLabel = item.label;

            regexp = new RegExp ('(' + srchTerm + ')', "ig");

            var strNewLabel = strNewLabel.replace(regexp,"<span style='font-weight:bold;color:Blue;'>$1</span>");

      return $( "<li></li>" )
          .data( "item.autocomplete", item )
          .append( "<a>" + strNewLabel + "</a>" )
          .appendTo( ul );

   };

});
like image 33
jmm Avatar answered Oct 21 '22 00:10

jmm


I've found that using the built in autocomplete filter to reduce your search space does the trick as well (and is much simpler):

source: function( request, response ) {
    var searchspace = availableTags;
    // split by space or however you want to split up your search phrase into terms
    var searchwords = request.term.split(" ");

    $.each(searchwords, function() {
        searchspace = $.ui.autocomplete.filter(searchspace, this);
    });

    // in case you don't want to return the whole thing, if your searchspace is large
    var mySlice = searchspace.slice(0, 10);
        response(mySlice);
    },
}
like image 31
Aaron Moronez Avatar answered Oct 21 '22 01:10

Aaron Moronez