2

I am creating a custom binding, named "myhandler". I need nothing in the initialize phase, and I do not want the update function to be executed the first time. The update member of ko.bindingHandlers, as said in the guide, is executed once at binding application, then whenever observable associated changes - I want to skip the binding application execution because it has not sense since other parts of the page are not ready for it.

In the observable associated, newID, passed in the html binding as follows, I have created a flag member in the view model, name bInitExecution (newID.bInitExecution).

 <div><input id="objID" name="objID" data-bind="value: newID, myhandler: newID" /></div>

The member, which holds if handler should perform things in the first phase, is not an observable (but I also tried making it so without any change), it is a boolean and in the model it is fixed to true or false as needed, if update has to be performed also at first time or not.

 newID = ko.observable();
 //.... some other data
 newID.bInitExecution = false

I expect that following code would skip first execution if bInitExecution is false, then execute always, while always execute if bInitExecution is true.

 ko.bindingHandlers.myhandler = {
      init: function init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
         //None needed here
      },
      update: function(element, valueAccessor, allBindings) {
         if (valueAccessor().bInitExecution===true) {
            //Do stuff
        }
        if (valueAccessor().bInitExecution===false) valueAccessor().bInitExecution=true;
     }
 };

The result is that, after the first execution, observables with bInitExecution set to true are always updated by myhandler, while the ones with bInitExecution set to false, even if valueAccessor().bInitExecution changes during binding apply as console.log before and after true assignment shows, without executing stuff, never executes myhandler.update again - as console.log placed on the head of the update function shows.

I do not understand why, someone has any idea? Thanks

Nillus
  • 1,131
  • 1
  • 14
  • 32

1 Answers1

2

In ko bindingHandler implementation, ko wraps the whole update function in a ko.dependentObservable (aka ko.computed). That's how and why ko runs your update function when data model changes.

It means if you didn't use the value of newID() (as ko.unwrap(valueAccessor()) or valueAccessor()()) in your update function, the final ko.dependentObservable wrapper IS NOT dependent on newID. Hence ko would not run it again when newID changes.

I guess you did not use the value of newID in your //Do stuff....

update

I missed this part. Even newID() is accessed in //Do stuff, the ko.computed wrapper will never get chance to run again. Because in the first run of it, newID is not accessed, in fact there is no ko.observable being accessed in the first run, so there is no dependency tracked by ko's auto tracking system.

huocp
  • 3,898
  • 1
  • 17
  • 29
  • 1
    Didn't know about update being a ko.computed. It didn't work because Do stuff uses newID(), but only if the if condition is true. When condition becomes true from false at the first update execution, somehow the update is not executed anymore - yet I don't understand why. Anyway, adding a dummy use of valueAccessor()() in top of update body (for example var t = valueAccessor()()), all runs fine. – Nillus Aug 07 '14 at 08:49
  • That is right. I missed that part. ko.computed re-tracks dependency everytime it runs. So it never had chance to depend on newID. – huocp Aug 07 '14 at 11:10
  • Very good point. I just discovered that 'update' function in a custom binding is a dependentObservable while looking at the call stack while having a break point reached in an instruction of the 'update' function. Knockout is very powerful but you have to know all theses internals knowledge. – Samuel Nov 26 '14 at 18:27