How to create an auto-complete combobox?

2019-01-03 04:40发布

Does any one know the best way to create an autocomplete combobox with Knockout JS templates?

I have the following template:

<script type="text/html" id="row-template">
<tr>
...
    <td>         
        <select class="list" data-bind="options: SomeViewModelArray, 
                                        value: SelectedItem">
        </select>
    </td>
...        
<tr>
</script>

Sometimes this list is long and I'd like to have Knockout play nicely with perhaps jQuery autocomplete or some straight JavaScript code, but have had little success.

In addition, jQuery.Autocomplete requires an input field. Any ideas?

9条回答
闹够了就滚
2楼-- · 2019-01-03 04:58

Minor improvements,

First of all these are some very useful tips, thank you all for sharing.

I'm using the version posted by Epstone with the following improvements:

  1. Display the label (instead of the value) when pressing up or down - apparently this can be done by handling the focus event

  2. Using an observable array as the data source (instead of an array)

  3. Added the disposable handler as suggested by George

http://jsfiddle.net/PpSfR/

...
conf.focus = function (event, ui) {
  $(element).val(ui.item.label);
  return false;
}
...

Btw, specifying minLength as 0 allows displaying the alternatives by just moving the arrow keys without having to enter any text.

查看更多
三岁会撩人
3楼-- · 2019-01-03 05:05

Here is my solution:

ko.bindingHandlers.ko_autocomplete = {
    init: function (element, params) {
        $(element).autocomplete(params());
    },
    update: function (element, params) {
        $(element).autocomplete("option", "source", params().source);
    }
};

Usage:

<input type="text" id="name-search" data-bind="value: langName, 
ko_autocomplete: { source: getLangs(), select: addLang }"/>

http://jsfiddle.net/7bRVH/214/ Compared to RP's it is very basic but maybe fills your needs.

查看更多
在下西门庆
4楼-- · 2019-01-03 05:08

I tried Niemeyer's solution with JQuery UI 1.10.x, but the autocomplete box simply didn't show up, after some searching i found a simple workaround here. Adding the following rule to the end of your jquery-ui.css file fixes the problem:

ul.ui-autocomplete.ui-menu {
  z-index: 1000;
}

I also used Knockout-3.1.0, so I had to replace ko.dependentObservable(...) with ko.computed(...)

In addition, if your KO View model contains some numeric value make sure you change the comparison operators: from === to == and !== to != , so that type conversion is performed.

I hope this helps others

查看更多
叼着烟拽天下
5楼-- · 2019-01-03 05:08

Another variation on Epstone's original solution.

I tried to use it but also found that the view model was only being updated when a value was typed manually. Selecting an autocomplete entry left the view model with the old value, which is a bit of a worry because validation still passes - it's only when you look in the database you see the problem!

The method I used is to hook the select handler of the jquery UI component in the knockout binding init, which simply updates the knockout model when a value is chosen. This code also incorporates the dispose plumbing from George's useful answer above.

init: function (element, valueAccessor, allBindingsAccessor) {

        valueAccessor.select = function(event, ui) {
            var va = allBindingsAccessor();
            va.value(ui.item.value);
        }

        $(element).autocomplete(valueAccessor);

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            $(element).autocomplete("destroy");
        });

    }
...
                    <input class="form-control" type="text" data-bind="value: ModelProperty, ko_autocomplete: { source: $root.getAutocompleteValues() }" />

This is now working pretty well. It is intended to work against a preloaded array of values on the page rather than querying an api.

查看更多
戒情不戒烟
6楼-- · 2019-01-03 05:12

Disposal needed....

Both of those solutions are great (with Niemeyer's being much more fine grained) but they both forget the disposal handling!

They should handle disposals by destroying jquery autocomplete (prevent memory leakages) with this:

init: function (element, valueAccessor, allBindingsAccessor) {  
....  
    //handle disposal (if KO removes by the template binding)
    ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
        $(element).autocomplete("destroy");
    });
}
查看更多
聊天终结者
7楼-- · 2019-01-03 05:14

I know this question is old, but I was also looking for a really simple solution for our team using this in a form, and found out that jQuery autocomplete raises an 'autocompleteselect' event.

This gave me this idea.

<input data-bind="value: text, valueUpdate:['blur','autocompleteselect'], jqAutocomplete: autocompleteUrl" />

With the handler simply being:

ko.bindingHandlers.jqAutocomplete = {
   update: function(element, valueAccessor) {
      var value = valueAccessor();

      $(element).autocomplete({
         source: value,
      });
   }    
}

I liked this approach because it keeps the handler simple, and it doesn't attach jQuery events into my viewmodel. Here is a fiddle with an array instead of a url as the source. This works if you click the textbox and also if you press enter.

https://jsfiddle.net/fbt1772L/3/

查看更多
登录 后发表回答