29

Does a jQuery plug-in exist for replacing select/combo box?

I tried SexyCombo, and it is as close to what I want, but it doesn't complete if you are writing from middle, only from beginning.

I have 2 levels of categories (20 top level categories, and with subcategories in total 120 categories), so when user is submitting an entry, he must find desired category as soon as possible.

So... 2 levels + autocomplete populate text even if you write middle letters.

Or any other solution?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kenan
  • 291
  • 1
  • 3
  • 3

5 Answers5

45

Have a look at the following example of the jQueryUI Autocomplete, as it is keeping a select around and I think that is what you are looking for. Hope this helps.

http://jqueryui.com/demos/autocomplete/#combobox

Lance
  • 5,655
  • 4
  • 30
  • 32
  • 11
    This is exactly why i love Stackoverflow. THX! – palmic Jan 08 '12 at 20:20
  • @Lance May, hai I am also looking for the same what u suggested. But I want to do that with ajax auto completion. Instead of static auto complete. Looking for a solution... – vissu Apr 19 '12 at 09:19
  • Unless I am misunderstanding you, Vissu, you're simply wanting this list to be returned from a remote location instead of being a hard-coded set of options. If that is correct, there is a remote sample on the same page (different anchor, but still the same demo) that may help http://jqueryui.com/demos/autocomplete/#remote . If that's not what you meant, please let me know. Thanks. – Lance Apr 19 '12 at 14:44
  • 1
    @Lance May, Thank you for your reply. As u said earlier in this page http://jqueryui.com/demos/autocomplete/#combobox, I want the same combobox. But When user click on the "down arrow" it should load all data from remote location and when user type a word in the "text field" area, then based on that condition it should load the relevant data. Finally my requirement is the combo box should be display as the same as combo box. Not a text field. Please ignore and let me know if I am asking any impossible or unusual thing. – vissu Apr 20 '12 at 09:04
  • 1
    @Vissu, I think what you're looking for would be a combobox-style solution with your data source being a remote location and not having the minimum search criteria. When you remove that two-character (I believe that's what they default to) search barrier, then call a search on the arrow-down click, you'll essentially just "search" on `""` and all results should return and then you can filter on text entry with the input's `.val()`. Sorry if I've missed the real question. – Lance Apr 20 '12 at 13:07
  • @Lance May, Thanks for you valuable suggestions. I will try like this and get back to you with result. – vissu Apr 23 '12 at 08:39
  • This works great, thanks. One issue though - $('#combobox').change(function () {..} stopped working. how can I combine? – Avi Kehat Mar 19 '17 at 15:33
  • To add back the "onChange" functionality, see: http://stackoverflow.com/a/18428586/1806397 – Avi Kehat Mar 19 '17 at 15:58
31

[edit] The lovely chosen jQuery plugin has been bought to my attention, looks like a great alternative to me.

Or if you just want to use jQuery autocomplete, I've extended the combobox example to support defaults and remove the tooltips to give what I think is more expected behaviour. Try it out.

(function ($) {
    $.widget("ui.combobox", {
        _create: function () {
            var input,
              that = this,
              wasOpen = false,
              select = this.element.hide(),
              selected = select.children(":selected"),
              defaultValue = selected.text() || "",
              wrapper = this.wrapper = $("<span>")
                .addClass("ui-combobox")
                .insertAfter(select);

            function removeIfInvalid(element) {
                var value = $(element).val(),
                  matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(value) + "$", "i"),
                  valid = false;
                select.children("option").each(function () {
                    if ($(this).text().match(matcher)) {
                        this.selected = valid = true;
                        return false;
                    }
                });

                if (!valid) {
                    // remove invalid value, as it didn't match anything
                    $(element).val(defaultValue);
                    select.val(defaultValue);
                    input.data("ui-autocomplete").term = "";
                }
            }

            input = $("<input>")
              .appendTo(wrapper)
              .val(defaultValue)
              .attr("title", "")
              .addClass("ui-state-default ui-combobox-input")
              .width(select.width())
              .autocomplete({
                  delay: 0,
                  minLength: 0,
                  autoFocus: true,
                  source: function (request, response) {
                      var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
                      response(select.children("option").map(function () {
                          var text = $(this).text();
                          if (this.value && (!request.term || matcher.test(text)))
                              return {
                                  label: text.replace(
                                    new RegExp(
                                      "(?![^&;]+;)(?!<[^<>]*)(" +
                                      $.ui.autocomplete.escapeRegex(request.term) +
                                      ")(?![^<>]*>)(?![^&;]+;)", "gi"
                                    ), "<strong>$1</strong>"),
                                  value: text,
                                  option: this
                              };
                      }));
                  },
                  select: function (event, ui) {
                      ui.item.option.selected = true;
                      that._trigger("selected", event, {
                          item: ui.item.option
                      });
                  },
                  change: function (event, ui) {
                      if (!ui.item) {
                          removeIfInvalid(this);
                      }
                  }
              })
              .addClass("ui-widget ui-widget-content ui-corner-left");

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

            $("<a>")
              .attr("tabIndex", -1)
              .appendTo(wrapper)
              .button({
                  icons: {
                      primary: "ui-icon-triangle-1-s"
                  },
                  text: false
              })
              .removeClass("ui-corner-all")
              .addClass("ui-corner-right ui-combobox-toggle")
              .mousedown(function () {
                  wasOpen = input.autocomplete("widget").is(":visible");
              })
              .click(function () {
                  input.focus();

                  // close if already visible
                  if (wasOpen) {
                      return;
                  }

                  // pass empty string as value to search for, displaying all results
                  input.autocomplete("search", "");
              });
        },

        _destroy: function () {
            this.wrapper.remove();
            this.element.show();
        }
    });
})(jQuery);
mcNux
  • 1,472
  • 1
  • 15
  • 13
4

I know this has been said earlier, but jQuery Autocomplete will do exactly what you need. You should check out the docs as the autocomplete is very customizable. If you are familiar with javascript then you should be able to work this out. If not I can give you a few pointers, as I have done this once before, but beware I am not well versed in javascript myself either, so bear with me on this.

I think the first thing you should do is just get a simple autocomplete text field working on your page, and then you can customize it from there.

The autocomplete widget accepts JSON data as it's 'source:' option. So you should set-up your app to produce the 20 top level categories, and subcategories in JSON format.

The next thing to know is that when the user types into your textfield, the autocomplete widget will send the typed values in a parameter called "term".

So let's say you first set-up your site to deliver the JSON data from a URL like this:

/categories.json

Then your autocomplete source: option would be 'source: /categories.json'.

When a user types into the textfield, such as 'first-cata...' the autocomplete widget will start sending the value in the 'term' parameter like this:

/categories.json?term=first-cata

This will return JSON data back to the widget filtered by anything that matches 'first-cata', and this is displayed as an autocomplete suggestion.

I am not sure what you are programming in, but you can specify how the 'term' parameter finds a match. So you can customize this, so that the term finds a match in the middle of a word if you want. Example, if the user types 'or' you code could make a match on 'sports'.

Lastly, you made a comment that you want to be able to select a category name but have the autocomplete widget submit the category ID not the name.

This can easily be done with a hidden field. This is what is shown in the jQuery autocomplete docs.

When a user selects a category, your JavaScript should update a hidden field with the ID.

I know this answer is not very detailed, but that is mainly because I am not sure what you are programming in, but the above should point you in the right direction. The thing to know is that you can do practically any customizing you want with this widget, if you are willing to spend the time to learn it.

These are the broad strokes, but you can look here for some notes I made when I implemented something similar to what you want in a Rails app.

Hope this helped.

Community
  • 1
  • 1
Oscar
  • 3,218
  • 2
  • 26
  • 26
3

This works great for me and I'm doing more, writing less with jQuery's example modified.

I defined the select object on my page, just like the jQuery ex. I took the text and pushed it to an array. Then I use the array as my source to my input autocomplete. tadaa.

$(function() {
   var mySource = [];
   $("#mySelect").children("option").map(function() {
      mySource.push($(this).text());
   });

   $("#myInput").autocomplete({
      source: mySource,
      minLength: 3
   });
}
1

jQuery 1.8.1 has an example of this under autocomplete. It's very easy to implement.

Anthony Potts
  • 8,842
  • 8
  • 41
  • 56