How I Stumbled With Knockout's Computed Observables
The first thing you learn about Knockout is about observables. The second thing is computed observables. They are dead simple. They even form part of the Hello World example. But then, the magic was not working for me. Here’s why:
In a nutshell computed observables are functions that are dependent on one or more other observables, and that will automatically update whenever any of these dependencies change.
On my usecase I wanted the computed to updated only if certain condition was met. So I used a variable and a good old if.
I also added a toggle function to be able to change the value of the
bindingActive variable from the UI. So the
fullName should get updated once I toggle the boolean variable. Guess what? it doesn’t!
Go ahead, give it a try. Turn on the toggle using the link and you’ll notice that the message does not appear as it did on the Hello World example.
I spent half a day looking for an answer of what I was doing wrong. Until I decided to do what I should’ve done in the first place. Instead of regarding some new technology as magic, I went ahead and read the documentation to actually understand how it works.
So here’s how the dependency tracking algorithm works according to KO documentation:
- Whenever you declare a computed observable, KO immediately invokes its evaluator function to get its initial value.
- While the evaluator function is running, KO sets up a subscription to any observables (including other computed observables) that the evaluator reads. The subscription callback is set to cause the evaluator to run again, looping the whole process back to step 1 (disposing of any old subscriptions that no longer apply).
- KO notifies any subscribers about the new value of your computed observable.
Notice what’s going on? Since
bindingActive initial value is false the tracking algorithm does not see the observables on it’s first past. Therefore the computed observable is not suscribed to update when any of the observables change!
How can we fix this?
Well a simple solution would be to define the toggle as an observable too. That way the computed observable suscribes to the toggle var observable and it gets recomputed when the variable changes.
Note that afterwards the step 2 of the tracking algorithm is designed to recognized the new observables that it missed the first time. That’s quite nice! Only in our case since no observable was seen at all the computed observable was never updated.
Here’s how such solution would look like:
Another way of solving this issue would be to call the observables for
lastName outside the if. That works too, but I like the other approach better.