Reputation: 7897
Overview
When creating a knockout custom binding that contains a call to a knockout default binding, my custom binding stops working after the first call.
To see the issue, in the JSFiddle example, change the selected item in the ddl once. Text changes as expected. Change it again, and nothing happens. Fail.
Details
I am seeing some odd behavior when extending the default knockout binding "html" with my own custom binding "htmlFade". The behavior I am looking for is the same as the html binding, but with a JQuery fade animation to fade DOM elements in and out.
Code samples below. A full JSFiddle example can be see here.
The HTML looks like this:
<select data-bind="options: names, value: selectedName"></select>
<data-bind="htmlFade : selectedName" class="main"></div>
The Json Data looks like this:
var viewModel = {
names: ko.observableArray(['Bob', 'Jon']),
selectedName: ko.observable('Bob')
};
The Custom Binding looks like this:
ko.bindingHandlers.htmlFade = {
init: function(element, valueAccessor) {
ko.bindingHandlers.html.init();
$(element).hide();
},
update: function(element, valueAccessor) {
$(element).fadeOut(700, function() {
ko.bindingHandlers.html.update(element, valueAccessor);
$(element).fadeIn(700);
});
}
};
I am intentionally deferring to the default html handler with the line "ko.bindingHandlers.html.update(element, valueAccessor)", because my goal is to extend the behavior, not recreate.
The problem I am having is that the above code works the first time select list is changed. After that it fails.
I created another JSFiddle example where instead of extending the behavior, I recreated it by adding the following line "http://jsfiddle.net/jamshall/kYwEE/1/" (copied from the knockout source for the default html binding) in place of the above referenced html.update call. This seems to work fine.
My question, then, is why does my Custom Binding stop working after the first call when I include a call to a default binding from withing it? Or, to make it simple, why does JSFiddle1 not work but JSFiddle2 work?
Thanks for any help
Upvotes: 4
Views: 657
Reputation: 114792
You can think of the update
function of a custom binding like a computed observable (Knockout does use computed observables to track dependencies when the bindings on an element are executed). So, in your custom binding you are not grabbing a dependency to the observable that you are bound against, because your code is being executed asynchronously.
In your update
, you would probably want to do something like:
update: function(element, valueAccessor) {
//just grab dependency
ko.utils.unwrapObservable(valueAccessor());
$(element).fadeOut(700, function() {
ko.bindingHandlers.html.update(element, valueAccessor);
$(element).fadeIn(700);
});
}
So, we just access the value of the observable to grab a dependency. ko.utils.unwrapObservable
just safely handles retrieving the value no matter if it is a non-observable or observable.
Updated sample: http://jsfiddle.net/rniemeyer/6UtsP/10/
Upvotes: 1