jQuery UI Autocomplete Multiple Values in Textbox
Asked Answered
Z

3

7

I need a simple autocomplete search functionality but also allowing users to type more than one value. I'm using jQuery UI's autocomplete widget (http://jqueryui.com/autocomplete/) and so far I've set the source to only search for the first letter in the suggestions. What I'd like to add now is the ability for users to search for multiple items from the same textbox. (i.e. after a comma suggestions are shown again)

I have been trying to search on how this could be done. The only thing I've managed to find is an option that could be added multiple: true (http://forum.jquery.com/topic/multiple-values-with-autocomplete). Thing is that it's not even listed in the documentation anymore so I don't know if the option has changed or doesn't exist anymore.

This is my code:

    var items = [ 'France', 'Italy', 'Malta', 'England', 
        'Australia', 'Spain', 'Scotland' ];

    $(document).ready(function () {
        $('#search').autocomplete({
            source: function (req, responseFn) {
                var re = $.ui.autocomplete.escapeRegex(req.term);
                var matcher = new RegExp('^' + re, 'i');
                var a = $.grep(items, function (item, index) {
                    return matcher.test(item);
                });
                responseFn(a);
            }
        });
    });

What I tried:

    var items = [ 'France', 'Italy', 'Malta', 'England', 
        'Australia', 'Spain', 'Scotland' ];

    $(document).ready(function () {
        $('#search').autocomplete({
            source: function (req, responseFn) {
                var re = $.ui.autocomplete.escapeRegex(req.term);
                var matcher = new RegExp('^' + re, 'i');
                var a = $.grep(items, function (item, index) {
                    return matcher.test(item);
                });
                responseFn(a);
            },
            multiple: true
        });
    });
Zuzana answered 5/10, 2013 at 15:6 Comment(0)
Z
5

To solve the issue of multiple strings in the same textbox AND include a regex to only show suggestions matching the start of the string I did the following:

    $('#search').autocomplete({
        minLength: 1,
        source: function (request, response) {
            var term = request.term;

            // substring of new string (only when a comma is in string)
            if (term.indexOf(', ') > 0) {
                var index = term.lastIndexOf(', ');
                term = term.substring(index + 2);
            }

            // regex to match string entered with start of suggestion strings
            var re = $.ui.autocomplete.escapeRegex(term);
            var matcher = new RegExp('^' + re, 'i');
            var regex_validated_array = $.grep(items, function (item, index) {
                return matcher.test(item);
            });

            // pass array `regex_validated_array ` to the response and 
            // `extractLast()` which takes care of the comma separation

            response($.ui.autocomplete.filter(regex_validated_array, 
                 extractLast(term)));
        },
        focus: function () {
            return false;
        },
        select: function (event, ui) {
            var terms = split(this.value);
            terms.pop();
            terms.push(ui.item.value);
            terms.push('');
            this.value = terms.join(', ');
            return false;
        }
    });

    function split(val) {
        return val.split(/,\s*/);
    }

    function extractLast(term) {
        return split(term).pop();
    }
Zuzana answered 7/10, 2013 at 8:36 Comment(0)
C
13

Try this:

  function split( val ) {
    return val.split( /,\s*/ );
  }

  function extractLast( term ) {
     return split( term ).pop();
   }

   $( "#search" )
        .autocomplete({
             minLength: 0,
             source: function( request, response ) {
                 response( $.ui.autocomplete.filter(
                     items, extractLast( request.term ) ) );
             },
             focus: function() {
                 return false;
             },
            select: function( event, ui ) {
                var terms = split( this.value );
                terms.pop();
                terms.push( ui.item.value );
                terms.push( "" );
                this.value = terms.join( ", " );
                return false;
            }
        });

SEE DEMO

Cordle answered 5/10, 2013 at 17:31 Comment(3)
Awesome that works! :) Only problem I have is that I can't seem to get it to work with the RegEx I have in the above code. Right now it's ignoring the RegExZuzana
It is correct, however it's not working with the RegEx I have. I'd like the suggestions to be matched with the first letter of the search not 'letter-by-letter'. That's the only issue I have. If you look at the code I've posted I have a RegEx to cater for this. Even though your code works, when I add the RegEx code I have above suggestions are only shown for the first word.Zuzana
Is there a way we can fetch the data from database instead of using the predefined list. Thanks in advance.Undersurface
Z
5

To solve the issue of multiple strings in the same textbox AND include a regex to only show suggestions matching the start of the string I did the following:

    $('#search').autocomplete({
        minLength: 1,
        source: function (request, response) {
            var term = request.term;

            // substring of new string (only when a comma is in string)
            if (term.indexOf(', ') > 0) {
                var index = term.lastIndexOf(', ');
                term = term.substring(index + 2);
            }

            // regex to match string entered with start of suggestion strings
            var re = $.ui.autocomplete.escapeRegex(term);
            var matcher = new RegExp('^' + re, 'i');
            var regex_validated_array = $.grep(items, function (item, index) {
                return matcher.test(item);
            });

            // pass array `regex_validated_array ` to the response and 
            // `extractLast()` which takes care of the comma separation

            response($.ui.autocomplete.filter(regex_validated_array, 
                 extractLast(term)));
        },
        focus: function () {
            return false;
        },
        select: function (event, ui) {
            var terms = split(this.value);
            terms.pop();
            terms.push(ui.item.value);
            terms.push('');
            this.value = terms.join(', ');
            return false;
        }
    });

    function split(val) {
        return val.split(/,\s*/);
    }

    function extractLast(term) {
        return split(term).pop();
    }
Zuzana answered 7/10, 2013 at 8:36 Comment(0)
B
0

If you want to implement the focus function instead of returning false, it's:

focus: function (event, ui) {
    var terms = split(this.value);
    terms.pop();
    terms.push(ui.item.value);
    this.value = terms.join(', ');
    return false;
},

If you do this though, you should probably extract commas from the values.

Also, you can replace lines 7-10 with a call to extractLast. And then you can get rid of your other extractLast because you already called it on term.

With all my changes:

$('#search').autocomplete({
    minLength: 1,
    source: function (request, response) {
        var term = extractLast(request.term),
            re = $.ui.autocomplete.escapeRegex(term),
            matcher = new RegExp('^' + re, 'i'),
            regex_validated_array = $.grep(items, function (item, index) {
                return matcher.test(item);
            }),
            mapped_array = regex_validated_array.map(function (item) {
              return value.replace(/,/g, '');
            });
        response($.ui.autocomplete.filter(mapped_array, term));
    },
    focus: function () {
        var terms = split(this.value);
        terms.pop();
        terms.push(ui.item.value);
        this.value = terms.join(', ');
        return false;
    },
    select: function (event, ui) {
        var terms = split(this.value);
        terms.pop();
        terms.push(ui.item.value);
        terms.push('');
        this.value = terms.join(', ');
        return false;
    }
});

function split(val) {
    return val.split(/,\s*/);
}

function extractLast(term) {
    return split(term).pop();
}
Bennion answered 11/3, 2022 at 18:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.