Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding keypress event on knockoutjs, observable not populated

Need a little help with knockoutjs and binding a keypress event. I'm trying to hook up knockout so that I pick up on the enter keypress from within a text box. So I can perform the same action as clicking a button. Its a little tricky to explain but hopefully this JsFiddle will demonstrate what I'm trying to achieve.

http://jsfiddle.net/nbnML/8/

The problem I have is that observable value is not getting updated and I think its something to do with an observable not being updated until focus moves away from the textbox?

Any solutions to this problem.

Thanks!

like image 367
mat-mcloughlin Avatar asked Jul 24 '12 10:07

mat-mcloughlin


People also ask

How do I set observable value in knockout?

To create an observable, assign the ko. observable function to the variable. A default value can be specified in the constructor of the call. Knockout then converts your variable into a function and tracks when the value changes, in order to notify the UI elements associated with the variable.

What are the types of binding supported by knockout JS?

Binding Values The binding value can be a single value, literal, a variable or can be a JavaScript expression.

What is binding in knockout JS?

A binding context is an object that holds data that you can reference from your bindings. While applying bindings, Knockout automatically creates and manages a hierarchy of binding contexts. The root level of the hierarchy refers to the viewModel parameter you supplied to ko. applyBindings(viewModel) .

What is two way data binding in knockout JS?

KO is able to create a two-way binding if you use value to link a form element to an Observable property, so that the changes between them are exchanged among them. If you refer a simple property on ViewModel, KO will set the form element's initial state to property value.


2 Answers

One option is to use the valueUpdate additional binding to force an update on each keypress. For example, you would do:

<input type="text" data-bind="value: InputValue, valueUpdate: 'afterkeydown', event: { keypress: RunSomethingKey }" />

If that is not what you are after, then really you would want to fire the element's change event in your handler. For example with jQuery, you would do something like: $(event.target).change();.

It would be better though to move this into a custom binding. Maybe something like (probably should check if the result of valueAccessor() is a function):

ko.bindingHandlers.enterKey = {
    init: function(element, valueAccessor, allBindings, vm) {
        ko.utils.registerEventHandler(element, "keyup", function(event) {
            if (event.keyCode === 13) {
                ko.utils.triggerEvent(element, "change");
                valueAccessor().call(vm, vm); //set "this" to the data and also pass it as first arg, in case function has "this" bound
            }

            return true;
        });
    }         
};

Here is your sample updated: http://jsfiddle.net/rniemeyer/nbnML/9/

like image 151
RP Niemeyer Avatar answered Oct 16 '22 03:10

RP Niemeyer


Don't discount submit bindings: http://knockoutjs.com/documentation/submit-binding.html

This takes care of some IE 9/10 gotchas such as the return key not updating the observable. With this taken care of you don't need to intercept keycode 13

html:

<form data-bind="submit:RunSomething">
 <input type="text" data-bind="value: InputValue" />
 <input type="submit" value="test" />
 <div data-bind="text: InputValue" />
</form>

code:

var ViewModel = function () {
    var self = this;
    self.InputValue = ko.observable('');

    self.RunSomething = function (ev) {
        window.alert(self.InputValue());
    }
}
ko.applyBindings(new ViewModel());

See this here:

http://jsfiddle.net/jnewcomb/uw2WX/

like image 33
jnewcomb Avatar answered Oct 16 '22 05:10

jnewcomb