I’ve been looking into Knockout JS recently and wanted to see how it could be integrated with JQuery (and JQuery.UI) to have an autocomplete field.
I also wanted to still have the original object supplying the label after a selection was made. This can be helpful to supply values to other fields afterwards, when you simply can’t regenerate it from the label alone.
I did find one example that I managed to change to be quite “simple” and generic.
I’ll run you through the sourcecode step by step:
We have a datasource that will supply the option list that will be used for the autocomplete functionality:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Currently it’s just an array containing objects with a
JQuery.UI Autocomplete widget
The original data array itself can be of any structure, but JQuery.UI’s autocomplete widget expects an array of strings as a minimum, they will be used for the label & value both, or you can supply an array of objects that have a
label and a value
property. Since we want a different value for the option’s
value we will use this object array. The
value properties are mandatory, but we are free to add our own properties, which we will do using the following function to convert our initial data array to a proper JQuery.UI autocomplete widget’s source array:
1 2 3 4 5 6 7 8 9
As you can see, we’ve added a
source property to hold our original object.
As you may know, KnockoutJS is a MVVM framework, and here is our ViewModel that will be used for the autocomplete widget:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
As you can see, it uses our previous function to convert the original data array to an options list. It also uses the KnockoutJS Observable to hold the selected value. We use the observable because we may want to know if it updates.
KnockoutJS’s observables are implementations from the Observable pattern and it will automatically let any instances that depend on the Observable know if it’s value is updated.
We use the
self property for a few reasons, it’s best explained in this stackoverflow answer. In short: it allows use to access the ViewModel from inside function scopes where
this would refer to the function being implemented instead of the parent object(the ViewModel).
KnockoutJS – Custom binding
To allow us to generically pass in the data for the Autocomplete Widget in the correct KnockoutJS manner, we will implement a custom binding.
I think it’s easier to understand it’s functionality when you see how it’s being used:
1 2 3 4
data-bind tag is KnockoutJS’s declarative way of binding ViewModel to the View (being HTML tags).
data-bind we can specify a binding handler which in this case is the
autocomplete binding handler. Built-in handlers are for example
text, which will just put the ViewModel’s value inside the bound HTML tag as text.
Our custom binding handler will be a bit more complex. It takes a parameter that is an object with 2 properties:
selected property must be a KnockoutJS Observable that will be updated with the option that was selected. The
options property will be the JQuery.UI AutoComplete’s source array with the options
The properties passed are properties on the ViewModel, being
The binding handler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
This is a lot to take in at once. You should focus on the following:
- Represents the passed in argument, being out object containing the observable for the selected options and the options array
- This is a function we call on each JQuery.UI Autocomplete widget’s events to set the selectedOption observable and to set the textbox to contain the label. It has the same parameters as the original widget events
- This is how we convert the textbox to the JQuery.UI Autocomplete widget.
- We override the default functionality in case an option is selected, the focus in the options list changes or the textbox value is changed.
- Default functionlity is to place the value of the option list in the textbox (which is strange that it doesn’t update it with the label).
valueAccessor parameter of the binding deserves some explanation. I think typically it’s not a complex object like in my case. So far I’ve seen people use multiple bindings to pass extra values to their binding handler. I don’t think it’s very clean so I just pass one object, which has multiple properties for representing all the parameters. Nothing is static typed so using this approach or the multiple binding’s is practically the same, in my opinion.
So now that we have our input, we read our individual parameters from it.
1 2 3 4 5 6 7 8 9 10 11 12
This is pretty straigthforward,
source property takes the list of options and then we override the events on the widget.
Update Element Value With Label
1 2 3 4 5 6 7 8 9 10 11 12 13 14
This function will stop the default behavior of updating the textbox with the option’s
value, on the
ui.item object, we want to use its
Finally, we update the selectedOption Observable with the whole item from the option array, containing the mandatory
value properties, as well as our own
object property containing the original data item.
Don’t forget the mandatory KnockoutJS initialization code:
1 2 3
1 2 3 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80