Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout deferUpdates conflict with 'if' binding

Tags:

knockout.js

I very often use the if binding in knockout to hide something, with the added bonus that I don't need to worry about null reference errors inside the if. In this example if address() is null then the whole block is removed so you avoid having to deal with null checking for every property. This would not be the case had I used the visible binding.

<div data-bind="if: address()">
    You live at:
    <p data-bind="text: address().street.toUpperCase()"></p>            
</div>

This is the simplest case above - and yes I would generally use this pattern with the <!-- ko --> comment syntax.

What is actually causing me problems is when I use a more complex computed value and enable the ko.options.deferUpdates option :

<div data-bind="if: hasAddress()">
    You live at:
    <p data-bind="text: address().street.toUpperCase()"></p>            
</div>

The simplest implementation of this computed observable might be something like this :

this.hasAddress = ko.computed(function () { return _this.address() != null; }); 

This all works great until I do the following:

1) set ko.options.deferUpdates = true before creating the observables.

2) address() will start off as null and everything is fine

3) set address() to { street: '123 My Street' }. Again everything works fine.

4) reset address() to null. I get a null error because address().street is null :-(

Here is a fiddle to illustrate the problem : https://jsfiddle.net/g5gvfb7x/2/

It seems that unfortunately due to the order in which the micro-tasks runs it tries to recalculate the text binding before the if binding and so you still get a null error that normally wouldn't occur.


I'm a little scared about this since I use this pattern a lot :-(

like image 242
Simon_Weaver Avatar asked Apr 11 '17 09:04

Simon_Weaver


People also ask

How do you write if condition in Knockout JS?

Note: Using “if” and “ifnot” without a container element-- ko --> and <! -- /ko --> comments act as start/end markers, defining a “virtual element” that contains the markup inside. Knockout understands this virtual element syntax and binds as if you had a real container element.

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?

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 Knockout used for?

Knockout is a JavaScript toolkit that allows you to connect HTML components to any data model. It is based on the MVVM paradigm and allows you to develop rich, responsive display and editor user interfaces with a clean underlying data model. Knockout. js works with a wide range of client and server-side technologies.


1 Answers

When using deferUpdates, Knockout internally uses a dirty event to notify all computed observables of a change in their dependencies and to schedule updates, which happens in depth-first order. The problem here occurs because bindings ignore the dirty event and wait for a change event, which will happen in a breadth-first order.

The fix has to happen in Knockout to make bindings respond to the dirty events. This has already been checked in for the upcoming version (3.5.0): https://github.com/knockout/knockout/issues/2226

like image 56
Michael Best Avatar answered Sep 17 '22 13:09

Michael Best