v3.0.0 Upgrade Notes

Knockout.js takes backward compatibility seriously. If you’re using a recent v2.x build, you will typically be able to drop in Knockout v3.0.0 without having to make any changes to your application code. Version 3.0.0 is intended to be fully backward-compatible except for a few carefully chosen design changes that enable major new features or fix longstanding issues.

1. Computed properties now notify only when their value changes

In Knockout v2.x, ko.computed properties would issue a “change” notification to their subscribers whenever they re-evaluated, even if the evaluation result was clearly identical to the previous one.

Many Knockout developers found this inconvenient because it caused unnecessary re-processing or duplicate actions. By popular demand we’ve changed the default behavior so that ko.computed does not issue “change” notifications after re-evaluation if the new value is definitely identical to the previous one (i.e., it’s a primitive - string/boolean/number/null/undefined - and equals the previous value).

This makes ko.computed consistent with ko.observable, which has always suppressed notifications if you reassign the same primitive value to it.

Restoring the earlier behavior

If you have a computed property that requires the v2.x behavior, i.e., you want repeated notifications even if the computed value is primitive and unchanged, you can enable this as follows:

myComputed.extend({ notify: 'always' });

2. Bindings are now refreshed independently

In Knockout v2.x, all bindings on the same element would refresh at the same time. Consider the following example:

<input type="checkbox" data-bind="visible: showTerms, checked: acceptsTerms" />

If your viewmodel changes acceptsTerms, then of course Knockout will re-run the checked binding to update the checkbox in the UI. But what you might not have realised is that, in v2.x, Knockout would also re-run the visible binding even though showTerms hasn’t changed. Although this usually caused no problems, it could lead to surprising bugs in advanced scenarios with custom binding handlers.

Knockout v3 has a greatly improved binding mechanism that refreshes all bindings independently and only when necessary. This improves performance and eliminates a whole category of potential problems with cross-binding dependencies. This change will only affect you if your code relies on v2.x’s undocumented implementation detail of cross-binding dependencies. In this case, you will need to update your code to stop relying on the obsolete behavior.

3. optionsCaption now HTML-encodes its output

In v2.x, optionsCaption did not HTML-encode its value. This was very inconvenient for developers who needed to display untrusted user-provided values, and was a security issue for developers who didn’t notice it. Knockout v3 now does HTML-encode optionsCaption values for display, making it consistent with the text binding which has always done so.

If you previously solved this by manually HTML-encoding strings before supplying them to optionsCaption, you’ll need to remove that logic otherwise the string will be double-encoded.

4. checked binding uses strict equality

Knockout v3 now checks for strict equality when comparing model values and element values for the checked binding. For instance, if you were to declare:

var foo = ko.observable(2);

and bind it to these elements:

<input type="radio" name="example" value="1" data-bind="checked: foo" />
<input type="radio" name="example" value="2" data-bind="checked: foo" />

the “2” radio button would not be checked because of the strict equality comparison between the observable and the element value. You could, of course, set the observable to a string value:

var foo = ko.observable('2');

and this would bind as expected. The preferred method, though, is to have the checked binding use numeric values by employing the checkedValue binding:

<input type="radio" name="example" data-bind="checked: foo, checkedValue: 2" />