Autocomplete

341 views
Skip to first unread message

MrTea

unread,
Sep 16, 2010, 10:09:15 AM9/16/10
to KnockoutJS
We need to use JQuery-UI's Autocomplete plugin with Knockout.

We have several text boxes in a row (similar to the shopping cart
example, but only text boxes).

When you type something in the first text box (Make), then the list of
Models for that Make should be loaded, and become the autocomplete
options for the next text box (Model).

This then continues for Type, and Engine.

We've tried subscribing to changes to Make, and loading the list of
Models from the server, into a local array...

this.Make.subscribe(function()
{ loadModels(this.Make()); }.bind(this));

loadModels, simply populates a local array with models for the
selected make.

We also added a bindingHandler to handle setting up the autocomplete.

ko.bindingHandlers.autocomplete = {
update: function(element, list) {
$(element).autocomplete({source: list});
}
};

Our text boxes then look like this...

<input data-bind="value: Make" />
<input class="autocomplete" data-bind="value: Model, autocomplete:
models" />

The problem is, that the autocomplete handler only kicks in when we
leave the text box (in this case the Model text box) by which time
it's too late to update the Autocomplete options.

Conversely, if we change this to work based on 'keyup', the model
doesn't get updated properly because when we select an item from the
autocomplete list and press tab (without typing the full name in) the
model only gets the first few letters which we manually typed in.

Any ideas?

Thanks,
Jon Hilton

fla...@gmail.com

unread,
Sep 16, 2010, 12:43:46 PM9/16/10
to KnockoutJS
Hi Jon

I had a go at implementing roughly what you describe (by modifying the
Cart Editor example) and it worked out pretty well - only a few
alterations to the example needed. Could you try out the code at
http://pastie.org/1163150 and see if it matches what you're trying to
do?

I didn't experience any problems with the autocomplete settings not
being applied early enough, so perhaps I haven't totally replicated
your scenario. If you could clarify how your scenario differs, I'd be
happy to try to discuss possible solutions with you.

By the way, autocomplete really is nice on this UI as it means the
whole thing can be operated only using the keyboard. This would be far
preferable to the drop-down lists if it was a UI you had to use
regularly.

Regards
Steve

MrTea

unread,
Sep 17, 2010, 3:54:41 AM9/17/10
to KnockoutJS
Hi Steve,

Thanks for your response, I hope Knockout gains traction amongst
developers, it certainly seems to be off to a flying start.

Re our Autocomplete example. The complication is that we have several
"layers" of autocomplete (several cascading text boxes) and a lot of
data so it's not practical to load the entire autocomplete graph (for
want of a better word) into memory when the user accesses the page.

So the question is how we change your example to load the relevant
autocomplete data as needed.

We had a stab at this as you can see here http://pastie.org/1164445
but then ran into the issue of the autocomplete data being loaded too
late.

Kind Regards,
Jon Hilton

On Sep 16, 5:43 pm, "st...@codeville.net" <fla...@gmail.com> wrote:
> Hi Jon
>
> I had a go at implementing roughly what you describe (by modifying the
> Cart Editor example) and it worked out pretty well - only a few
> alterations to the example needed. Could you try out the code athttp://pastie.org/1163150and see if it matches what you're trying to

fla...@gmail.com

unread,
Sep 21, 2010, 8:32:16 AM9/21/10
to KnockoutJS
Hi Jon

Ah, I see what you mean. Looking at your code, I think there were
actually two issues:

[1] You need to make your "makes", "models", etc. arrays observable
otherwise changing them isn't going to be reflected in the UI
[2] The jQuery UI autocomplete facility requires you to use some
different syntax if you want to change what autocomplete options are
associated with a form field that the user has already got focused.
Specifically, you have to trigger its "setOptions" event, and then it
will update properly.

To see how making these changes gets it to work, check out the code at
http://pastie.org/1172054. A few more points to note:

* Instead of having global arrays of autocomplete data (e.g.,
"models", "engines", etc.), I've made the autocomplete data a separate
property of each line. That way you can edit multiple lines at the
same time, and they each display the autocomplete options relating to
themselves, independently of the other lines.

* To ensure that any characters the user has typed into a box before
the autocomplete appears aren't erased when it does appear, I've used
"valueUpdate: 'afterkeydown'". This keeps the view model instantly in
sync with the view. Without this, things still work, but if you happen
to be pressing a key at the wrong moment, your key press could be
wiped out.

IMPORTANT: I've only just added 'afterkeydown' support to KO. To see
this example code working, be sure to use the latest Knockout code
from http://github.com/SteveSanderson/knockout/tree/master/build/output/

Cheers
Steve


On Sep 17, 8:54 am, MrTea <hilton....@gmail.com> wrote:
> Hi Steve,
>
> Thanks for your response, I hope Knockout gains traction amongst
> developers, it certainly seems to be off to a flying start.
>
> Re our Autocomplete example. The complication is that we have several
> "layers" of autocomplete (several cascading text boxes) and a lot of
> data so it's not practical to load the entire autocomplete graph (for
> want of a better word) into memory when the user accesses the page.
>
> So the question is how we change your example to load the relevant
> autocomplete data as needed.
>
> We had a stab at this as you can see herehttp://pastie.org/1164445
> but then ran into the issue of the autocomplete data being loaded too
> late.
>
> Kind Regards,
> Jon Hilton
>
> On Sep 16, 5:43 pm, "st...@codeville.net" <fla...@gmail.com> wrote:
>
>
>
> > Hi Jon
>
> > I had a go at implementing roughly what you describe (by modifying the
> > Cart Editor example) and it worked out pretty well - only a few
> > alterations to the example needed. Could you try out the code athttp://pastie.org/1163150andsee if it matches what you're trying to

Craig S

unread,
Sep 22, 2010, 4:02:45 PM9/22/10
to KnockoutJS
I can get the autocomplete for the "Make" textbox to work. But the
Model never works. I'm not sure the subscribe function is getting
called.

Thanks,
Craig


On Sep 21, 8:32 am, "st...@codeville.net" <fla...@gmail.com> wrote:
> Hi Jon
>
> Ah, I see what you mean. Looking at your code, I think there were
> actually two issues:
>
> [1] You need to make your "makes", "models", etc. arrays observable
> otherwise changing them isn't going to be reflected in the UI
> [2] The jQuery UI autocomplete facility requires you to use some
> different syntax if you want to change what autocomplete options are
> associated with a form field that the user has already got focused.
> Specifically, you have to trigger its "setOptions" event, and then it
> will update properly.
>
> To see how making these changes gets it to work, check out the code athttp://pastie.org/1172054. A few more points to note:
>
> * Instead of having global arrays of autocomplete data (e.g.,
> "models", "engines", etc.), I've made the autocomplete data a separate
> property of each line. That way you can edit multiple lines at the
> same time, and they each display the autocomplete options relating to
> themselves, independently of the other lines.
>
> * To ensure that any characters the user has typed into a box before
> the autocomplete appears aren't erased when it does appear, I've used
> "valueUpdate: 'afterkeydown'". This keeps the view model instantly in
> sync with the view. Without this, things still work, but if you happen
> to be pressing a key at the wrong moment, your key press could be
> wiped out.
>
> IMPORTANT: I've only just added 'afterkeydown' support to KO. To see
> this example code working, be sure to use the latest Knockout code
> fromhttp://github.com/SteveSanderson/knockout/tree/master/build/output/
>
> Cheers
> Steve
>
> On Sep 17, 8:54 am, MrTea <hilton....@gmail.com> wrote:
>
>
>
> > Hi Steve,
>
> > Thanks for your response, I hope Knockout gains traction amongst
> > developers, it certainly seems to be off to a flying start.
>
> > Re our Autocomplete example. The complication is that we have several
> > "layers" of autocomplete (several cascading text boxes) and a lot of
> > data so it's not practical to load the entire autocomplete graph (for
> > want of a better word) into memory when the user accesses the page.
>
> > So the question is how we change your example to load the relevant
> > autocomplete data as needed.
>
> > We had a stab at this as you can see herehttp://pastie.org/1164445
> > but then ran into the issue of the autocomplete data being loaded too
> > late.
>
> > Kind Regards,
> > Jon Hilton
>
> > On Sep 16, 5:43 pm, "st...@codeville.net" <fla...@gmail.com> wrote:
>
> > > Hi Jon
>
> > > I had a go at implementing roughly what you describe (by modifying the
> > > Cart Editor example) and it worked out pretty well - only a few
> > > alterations to the example needed. Could you try out the code athttp://pastie.org/1163150andseeif it matches what you're trying to

fla...@gmail.com

unread,
Sep 22, 2010, 5:05:00 PM9/22/10
to KnockoutJS
Craig, are you definitely using the latest version of Knockout? As I
mentioned, support for the "afterkeydown" event was only added in the
latest version that you can get from http://github.com/SteveSanderson/knockout/tree/master/build/output/.

Regards
Steve
> > > > alterations to the example needed. Could you try out the code athttp://pastie.org/1163150andseeifit matches what you're trying to

Craig S

unread,
Sep 22, 2010, 5:12:29 PM9/22/10
to KnockoutJS
Nice! That worked. thanks!

On Sep 22, 5:05 pm, "st...@codeville.net" <fla...@gmail.com> wrote:
> Craig, are you definitely using the latest version of Knockout? As I
> mentioned, support for the "afterkeydown" event was only added in the
> latest version that you can get fromhttp://github.com/SteveSanderson/knockout/tree/master/build/output/.
> > > > > alterations to the example needed. Could you try out the code athttp://pastie.org/1163150andseeifitmatches what you're trying to

David

unread,
Sep 29, 2010, 10:10:25 PM9/29/10
to KnockoutJS
I just added autocomplete to my project based on Steve's pastie. Just
wanted to note how I got mine working.

Because:
- I'm using Autocomplete from jQuery.UI 1.8
- I was binding to an int property rather than to a string property

I changed the autocomplete function slightly to:

ko.bindingHandlers.autocomplete = {
update: function(element, dataSource, allBindings) {
var propertyName = allBindings.autocompleteText;
var autoCompletionValues = ko.utils.arrayMap(dataSource,
function(item) { return item[propertyName].toString() });
$(element).autocomplete({source: autoCompletionValues});
}
};

With that change it worked perfectly for me.

Thanks,
David

On Sep 17, 5:43 am, "st...@codeville.net" <fla...@gmail.com> wrote:
> Hi Jon
>
> I had a go at implementing roughly what you describe (by modifying the
> Cart Editor example) and it worked out pretty well - only a few
> alterations to the example needed. Could you try out the code athttp://pastie.org/1163150and see if it matches what you're trying to

Richard Tasker

unread,
Oct 25, 2010, 4:14:01 AM10/25/10
to KnockoutJS
Morning Steve,

I am using Knockout with the autocomplete as in your example above.
Our testing has noticed a small issue of when you select an item from
the Autocomplete list using the mouse then mouse click into the next
text box, the key down events are not firing therefore the fields in
the model are not being updated. I have tried to fix the problem but
ended up creating an endless loop of the autocomplete suggestions
appearing when I select a value.

Regards
Rich

On Sep 30, 3:10 am, David <j.david.w...@gmail.com> wrote:
> I just added autocomplete to my project based on Steve's pastie.  Just
> wanted to note how I got mine working.
>
> Because:
> - I'm using Autocomplete from jQuery.UI 1.8
> - I was binding to an int property rather than to a string property
>
> I changed the autocomplete function slightly to:
>
>   ko.bindingHandlers.autocomplete = {
>        update: function(element, dataSource, allBindings) {
>            var propertyName = allBindings.autocompleteText;
>            var autoCompletionValues = ko.utils.arrayMap(dataSource,
> function(item) { return item[propertyName].toString() });
>            $(element).autocomplete({source: autoCompletionValues});
>        }
>     };
>
> With that change it worked perfectly for me.
>
> Thanks,
> David
>
> On Sep 17, 5:43 am, "st...@codeville.net" <fla...@gmail.com> wrote:
>
>
>
>
>
>
>
> > Hi Jon
>
> > I had a go at implementing roughly what you describe (by modifying the
> > Cart Editor example) and it worked out pretty well - only a few
> > alterations to the example needed. Could you try out the code athttp://pastie.org/1163150andsee if it matches what you're trying to

fla...@gmail.com

unread,
Oct 26, 2010, 4:45:45 AM10/26/10
to KnockoutJS
It seems that the Autocomplete plugin raises a nonstandard event after
you pick from the menu with the mouse, so to catch it (and treat it
the same as a keystroke) you can do something like the following:

[1] Change your ko binding to update values after a new custom event
called 'autocompleteChange':

<td><input data-bind="autocomplete: SuggestedMakes, value: Make,
valueUpdate: 'autocompleteChange'" /></td>
<td><input data-bind="autocomplete: SuggestedModels, value: Model,
valueUpdate: 'autocompleteChange'" /></td>
<td><input data-bind="autocomplete: SuggestedTypes, value: Type,
valueUpdate: 'autocompleteChange'" /></td>
<td><input data-bind="autocomplete: SuggestedEngines, value:
Engine, valueUpdate: 'autocompleteChange'" /></td>

[2] Use a jQuery "live" binding to convert the two events raised by
autocomplete into this new custom event:

// Treat autocomplete as having done something when either you
pick from the menu, or
// asynchronously after a keystroke
$("input").live("result", function() { $
(this).trigger("autocompleteChange"); });
$("input").live("keydown", function() { setTimeout(function() { $
(this).trigger("autocompleteChange") }.bind(this), 0) });

That seems to do it for me, though it is a bit fiddly trying to work
out exactly what events get raised and when.

Regards
Steve
> > > alterations to the example needed. Could you try out the code athttp://pastie.org/1163150andseeif it matches what you're trying to
Reply all
Reply to author
Forward
0 new messages