Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
232 views
in Technique[技术] by (71.8m points)

javascript - jQueryUI Autocomplete - how to match search words with a list of keywords and show the matched results?

I'm trying to use jQueryUI Autocomplete to implement a site quick searching feature for various functionality pages in my site. I guess you could say it is like Google Instant Search but it's indexing pages on my site.

So when they search for "create" it will bring up the Create user option and the Create organisation option. When they search for "create use" it will only show the Create User option. Then they can click on the results and it will load up that page. These are just some of the links. But as you can see, each page will have some various keywords/synonyms that would all point to the same page.

Ok so the checkSearchWordsMatchKeywords function at the end there definitely works because I've tested it. What isn't working is I don't know what I'm supposed to return from the jQueryUI search: function.

Also if you know how to optimise that checkSearchWordsMatchKeywords() function then I'm all ears. :)

Edit: updated with working solution below (works with jQueryUI 1.9.x):

var links = [
{
    keywords: ['create', 'add', 'make', 'insert', 'user'],
    label: "Create user",
    desc: "Create a user in the system",
    url: 'http://mysite.com/user/create/'
},
{
    keywords: ['create', 'add', 'make', 'insert', 'organisation'],
    label: "Create organisation",
    desc: "Create an organisation in the system",
    url: 'http://mysite.com/organisation/create/'
}];

$('#searchTerms').autocomplete(
{
    minLength: 2,
    source: function(request, response)
    {
        var matched = [];
        var numOfLinks = links.length;

        // Get entered search terms (request.term) from user and search through all links keywords
        for (var k = 0; k < numOfLinks; k++)
        {
            // If it matches, push the object into a new array
            if (checkSearchWordsMatchKeywords(request.term, links[k].keywords))
            {
                matched.push(links[k]);
            }
        }

        // Display the filtered results
        response(matched);
    },
    focus: function(event, ui)
    {
        // When the item is selected, put the label text into the search box
        $('#searchTerms').val(ui.item.label);
        return false;
    },
    select: function(event, ui)
    {
        // Put the selected link's label in the text box and redirect to the url
        $('#searchTerms').val(ui.item.label);

        // Redirect to the page using .href so the previous page is saved into the user's browser history
        window.location.href = ui.item.url;
        return false;
    }
})
.data('autocomplete')._renderItem = function(ul, item)
{
    // Show a description underneath the link label. Using the hyperlink here too so that mouse click still works
    return $('<li></li>')
        .data('item.autocomplete', item )
        .append('<a href="' + item.url + '"><b>' + item.label + '</b><br>' + item.desc + '</a>')
        .appendTo(ul);
};

/**
 * Check that each word in a search string matches at least one keyword in an array
 * E.g. searchWords = 'create use'  and  keywords = ['create', 'add', 'make', 'insert', 'user'] will return true
 */
function checkSearchWordsMatchKeywords(searchString, keywords)
{
    var searchWords = searchString.toLowerCase().split(' ');    // Lowercase the search words & break up the search into separate words
    var numOfSearchWords = searchWords.length;                  // Count number of search words
    var numOfKeywords = keywords.length;                        // Count the number of keywords
    var matches = [];                                           // Will contain the keywords that matched the search words

    // For each search word look up the keywords array to see if the search word partially matches the keyword
    for (var i = 0; i < numOfSearchWords; i++)
    {
        // For each keyword
        for (var j = 0; j < numOfKeywords; j++)
        {   
            // Check search word is part of a keyword
            if (keywords[j].indexOf(searchWords[i]) != -1)
            {
                // Found match, store match, then look for next search word
                matches.push(keywords[j]);
                break;
            }
        }
    }

    // Count the number of matches, and if it equals the number of search words then the search words match the keywords
    if (matches.length == numOfSearchWords)
    {
        return true;
    }

    return false;
}

Jump to page

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I don't the "search" event is the place to do what you're after. You should rather implement the source option as a callback:

$("#searchTerms").autocomplete({
    ...
    source: function(request, response) {        
        var matched = [];
        // Search "request.term" through all links keywords
        for (var k = 0; k < links.length; k++) {
            if (checkSearchWordsMatchKeywords(request.term, links[k]['keywords'])) {
                matched.push(links[k]);
            }
        }
        // display the filtered results
        response(matched);
    }
});
  • the request object contains the term property which is the text that is entered in the input
  • the response parameter is callback that you should call to display the results.

So basically, you get and filter your data, and pass it to response() to display the menu.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...