0

I am using a (slightly modified) jQuery autocomplete combobox to transform a <select> into a live search <input>. The problem is the underlying <select> looks like:

<select department>
<option value="12345">Computer Engineering</option>
<option value="01234">Computer Science</option>
  :
</select>

so when the user selects their choice, the department number is put in the <input> which looks fugly and confusing (but it is the correct value to submit).

Do I have any possibilities other than to further modify the combobox widget to add an <input type='hidden'> and to (somehow?) prevent the submission of the <input type=text> ?

EDIT: As @Pierre's link shows, the combobox's <input type='text'> has no name so it isn't submitted, so all that needs to happen is to put the selected option's label rather than it's value into the text input.

John Hascall
  • 9,176
  • 6
  • 48
  • 72

2 Answers2

1

Default jquery ui autocomplete behavior seems to display value data. You can change this, see this thread jQuery autocomplete shows value instead of label

Otherwise, you have other solutions that work correctly out of the box :

it will solve your problem with the <input> tag containing the id...

PierreN
  • 968
  • 4
  • 11
0

Here is the code I ended up with, perhaps it will be helpful to others. It's a composition of the combobox and category examples from the jQuery UI autocomplete page. Note: because I don't dynamically modify the underlying select, I scan the select only once -- in the combobox _create function -- if modification is a possibility, this should be moved into the _source function.

$(document).ready(function() {
  jQuery.widget("custom.autooptgroup", jQuery.ui.autocomplete, {
    _create: function() {
      this._super();
      this.widget().menu(
        "option",
        "items",
        "> :not(.ui-autocomplete-category)"
      );
    },
    _renderMenu: function(ul, items) {
      var self = this;
      var prevCat = "";
      var li;
      jQuery.each(items, function(index, item) {
        li = "<li class='ui-autocomplete-category'>";
        if (item.category != prevCat) {
          ul.append(li + item.category + "</li>");
          prevCat = item.category;
        }
        li = self._renderItemData(ul, item);
        if (item.category) {
          li.attr(
            "aria-label",
            item.category + " : " + item.label
          );
        }
      });
    }
  });
  jQuery.widget("custom.combobox", {
    _create: function() {
      this.wrapper = $("<span>")
        .addClass("custom-combobox")
        .insertAfter(this.element);
      this.olvc = [];
      var ogroups = this.element[0].children;
      for (var i = 0; i < ogroups.length; ++i) {
        var ogroup = ogroups[i];
        if (ogroup.nodeName == "OPTION") {
          var opt = ogroup
          var txt = opt.text;
          var val = opt.value;
          this.olvc.push({
            option: opt,
            label: txt,
            value: val,
            category: ""
          });
        } else {
          var cat = ogroup.label;
          var opts = ogroup.children;
          for (var j = 0; j < opts.length; ++j) {
            var opt = opts[j];
            var txt = opt.text;
            var val = opt.value;
            this.olvc.push({
              option: opt,
              label: txt,
              value: val,
              category: cat
            });
          }
        }
      }

      this.element.hide();
      this._createAutocomplete()
    },

    /* :selected will return the first option if none are explicitly selected */
    /* we don't want this so we look at the selected attribute to see if the */
    /* option returned by :selected is really selected */
    _createAutocomplete: function() {
      var self = this;
      var selected = this.element.find(":selected");
      var really = (selected.attr('selected') != null);
      var value = really ? (selected.val() ? selected.text() : "") : "";

      this.input = $("<input>")
        .appendTo(this.wrapper)
        .val(value)
        .attr("title", "")
        .attr("size", "32")
        .attr("placeholder", self.element.attr('placeholder'))
        .addClass(
          "custom-combobox-input " +
          "ui-widget ui-widget-content " +
          "ui-state-default ui-corner-left"
        )
        .autooptgroup({
          delay: 0,
          minLength: 0,
          source: jQuery.proxy(this, "_source"),
          select: function(event, ui) {
            ui.item.option.selected = true;
            self._trigger("select", event, {
              item: ui.item.option
            });
            $(this).val(ui.item.label);  /* label, not value for us! */
            event.preventDefault();
          },
          change: function(event, ui) {
            var value = self.input.val();
            var valueLowerCase = value.toLowerCase();
            var valid = false;

            if (ui.item) return;

            self.element.children("option").each(function() {
              if ($(this).label().toLowerCase() === valueLowerCase) {
                this.selected = valid = true;
                return false;
              }
            });

            if (valid) return;

            self.input
              .val("")
              .attr("title", value + " didn't match any item")
              .tooltip("open");
            self.element.val("");
            self._delay(function() {
              this.input.tooltip("close").attr("title", "");
            }, 2500);
          }
        })
        .tooltip({
          classes: {
            "ui-tooltip": "ui-state-highlight"
          }
        });
    },

    _source: function(request, response) {
      response(jQuery.ui.autocomplete.filter(
        this.olvc, request.term
      ));
    },

    _destroy: function() {
      this.wrapper.remove();
      this.element.show();
    }
  });


  $('.example').combobox({
    delay: 0,
    minLength: 0
  });

});
.ui-autocomplete {
  text-align: left;
  max-height: 500px;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 20px;
}

.ui-autocomplete-category {
  font-weight: bold;
}

.ui-widget {
  font-family: Nimbus Sans, arial, helvetica, verdana, sans-serif;
  font-size: 1em;
}
<link href="https://code.jquery.com/ui/1.11.1/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<script src="https://code.jquery.com/ui/1.11.1/jquery-ui.min.js"></script>

<span style='font-weight: bold'>States and Such</span><br>
<select name='locations' class='example' placeholder='Select Location'>
  <option value='MP'>Northern Mariana Islands</option>
  <option value='PR'>Puerto Rico</option>
  <option value='VI'>US Virgin Islands</option>
  <optgroup label='East'>
    <option value='NH'>New Hampshire</option>
    <option value='NJ'>New Jersey</option>
    <option value='NY'>New York</option>
    <option value='VT'>Vermont</option>
  </optgroup>
  <optgroup label='Midwest'>
    <option value='IA'>Iowa</option>
    <option value='MN'>Minnesota</option>
    <option value='ND'>North Dakota</option>
    <option value='SD'>South Dakota</option>
    <option value='WS'>Wisconsin</option>
  </optgroup>
  <optgroup label='South'>
    <option value='FL'>Florida</option>
    <option value='NC'>North Carolina</option>
    <option value='NM'>New Mexico</option>
    <option value='SC'>South Carolina</option>
    <option value='TX'>Texas</option>
  </optgroup>
  <optgroup label='West'>
    <option value='CA'>California</option>
    <option value='OR'>Oregon</option>
    <option value='WA'>Washington</option>
  </optgroup>
</select>
John Hascall
  • 9,176
  • 6
  • 48
  • 72