I have http://jsfiddle.net/ksCSn/1/
HTML
<input type="text" data-bind="
value: title,
hasfocus: edit,
onEnter: stopEdit" />
<p data-bind="text: title"></p>
JS
ko.bindingHandlers.onEnter = {
init: function(element, valueAccessor, _, viewModel) {
ko.utils.registerEventHandler(element, 'keydown', function(evt) {
if (evt.keyCode === 13)
valueAccessor().call(viewModel);
});
}
}
function ViewModel() {
this.title = ko.observable("default value");
this.edit = ko.observable(false);
this.stopEdit = function() {
this.edit(false);
// If the edit update is in a timeout, then it works
// var edit = this.edit;
// setTimeout(function() { edit(false); }, 0);
};
}
ko.applyBindings(new ViewModel());
How come when the Enter key is pressed while editing in the input field, the value does not update?
And if I change the edit update so that it is queued up as a timeout, then it works. Why is that?
This is because of a "bug" in Knockout (see https://github.com/SteveSanderson/knockout/issues/321) that causes all bindings to update together. When you change your edit
property, it updates the hasfocus
binding to blur the field, and, because of the bug, updates the value
binding too. Because bindings are run in the order listed, the value
binding gets updated first, which overwrites the field with the value of title
in the view model.
A simple change that fixes this is to re-order the bindings so that hasfocus
will run first: http://jsfiddle.net/mbest/ksCSn/8/
You should use Blur when pressing enter, I've adjusted your JS Fiddle
But m.b you should try to use another event to update value instead of pressing enter for changing value? For example afterkeydown: Js Fiddle
Also see KnockoutJS documentation
ValueAccessor is a function that will evaluate either to a plain property or a ko.observable, depending on what you passed to the binding.
In your example you are passing the stopEdit function, hence:
valueAccessor().call(viewModel)
equals to
viewModel.stopEdit.call(viewModel)
Passing viewModel to the function will reset the scope from this to your viewModel.
In your example this will efectively set the edit property of your viewModel to false, thus You could also write this as
viewModel.edit(false);
The issue here is you are mixing up events, see U10's answer for a better approach on tackling this issue.