Twitter About Home

Knockout v2.3.0 released; v3.0.0 beta available

Lots of new goodies for Knockout.js developers today! You can download version 2.3.0 final or 3.0.0 beta from the downloads page right now.

Published Jul 9, 2013

Why two new versions on the same day? The KO team and community has been hard at work preparing for the next phase of the library’s evolution, and we decided to roll it out in the form of a choice:

  • Get v2.3.0 if you just want all the bugfixes, perf improvements, and small features we’ve added in recent months. This is ideal for existing production apps.
  • Get v3.0.0-beta if you want the kickass new binding system (plus all the v2.3.0 enhancements) which has tonnes of powerful new extensibility potential. It’s almost-but-not-100% back-compatible with the older system – details below.

What’s new in 2.3.0?

Although KO 2.3.0 is primarily a package of compatibility/performance improvements and bugfixes, we sneaked in a few new features too:

  • ko.observable, ko.computed and other non-DOM-related parts of KO can now run on the server in Node.js. NPM package available.
  • The options binding has been rebuilt and made much smarter:
    • It now inserts and removes <options> nodes incrementally (rather than recreating them all) as your underlying array changes, leading to much better performance on older browsers.
    • A new optionsAfterRender callback lets you add custom code to modify <options> nodes as they are added to the document, in case you need this to interoperate with third-party DOM libraries
  • The template binding now allows use of an observable template name. This gives you an extra way of switching templates dynamically at runtime.
  • The css binding now allows use of any legal CSS class name. Previously it didn’t allow dots or slashes in class names.
  • ko.unwrap is the new, shorter name for ko.utils.unwrapObservable. Don’t worry – the old name still works too!

Bugfixes and compatibilty/perf improvements include:

  • KO will now warn you with an error if you try to apply bindings to the same element more than once (this was always an error; we just didn’t report it before)
  • The hasfocus and options bindings now work around additional edge-case browser quirks, e.g., during page load when running in an iframe in IE9 in compatibility mode (seriously!). This gives you a more consistent developer experience.
  • Observable arrays have better handling of unexpected parameters (for example, when initialized with non-array values).
  • The template binding now has more predictable handling of malformed HTML markup
  • ko.toJS now usefully handles String/Number/Boolean object-type properties (as opposed to string/number/bool primitives, which have always worked)
  • ko.computed now recovers from exceptions thrown during your evaluation callback. Previously, an evaluator exception would stop all future updates for that ko.computed.
  • Better whitespace handling in string-based templates (e.g., you can now put spaces around the equals character in data-bind = '…', if you care about that kind of thing).
  • General perf improvements (e.g., we avoid evaluating scrollTop when not absolutely necessary, as it triggers a rendering reflow).
  • More than 20 bugfixes for minor issues

Along the way, we improved some of the KO engineering processes to help us keep the momentum and stability high:

  • Ported all specs to the excellent Jasmine testing framework (thanks Chris!), so they can run in a wider range of environments
  • Simplified build system by removing all batch files
  • Automatic test runners everywhere!
    • The build script now runs all specs in PhantomJS if installed
    • The build script also runs specs for the Node-compatible subset of KO directly in Node (not via PhantomJS).
    • All specs run in all supported browsers (even IE6 and Safari for iOS 5 :) ) on every push to GitHub thanks to the excellent Testling service.

For a more detailed list, see the 2.3.0 release notes page.

What’s coming in 3.0.0?

v3 is a forward-looking release that focuses on how KO binds your models to your DOM:

  • It aims to open up powerful new extensibility possibilities at the heart of KO’s binding system. This means, for example, you can define your own new custom markup syntaxes.
  • Along the way, it fixes some longstanding complications in the binding mechanism. For example, it guarantees that bindings update independently and in the desired relative order, so there’s much less scope for surprising edge-case behaviors.

So, how does that actually look?

Node and binding rewriting

With v3, advanced KO developers can define custom syntaxes by providing callbacks that rewrite DOM nodes and binding strings during the binding process.

As an example of a node rewriter, here’s a custom binding syntax I just put together. It lets you write `` to insert the value of arbitrary viewmodel expressions in your DOM, so that you rarely need to bother using the text binding. Because of how node rewriting works, it automatically has full support for observable values, being embedded in foreach loops etc.:

Such syntaxes can be distributed as KO plugins. Popular ones might end up in KO core.

Many more advanced scenarios are possible. For example, developers could create a “widgets” plugin that rewrites custom elements such as <orderLine> with the output from some other markup defined in <template id='orderLine'>…</template>.

Independent and ordered bindings

Until v3, if you had a binding like this:

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

… then any changes to needsTerms would cause both visible and checked to be re-evaluated, so the “checked” state of the checkbox would be reapplied. That’s rarely a problem, but it’s not great for performance and there were some rare edge cases where custom and even built-in bindings could interact in unexpected ways.

Also, the order in which bindings were applied was given by their left-to-right order in your binding attribute (so in this case, visible was applied before checked). Again, that’s almost always OK, and usually what you actually want. But again there could be edge-case scenarios with custom or even built-in bindings interacted in unexpected ways depending on order.

v3 fixes this by ensuring that bindings only refresh when their bound model state has changed at a more fine-grained level. So in the above example, changing needsTerms would not cause checked to refresh. Also v3 lets bindings declare order dependencies, so if for some reason it was important for checked to run before visible, we could ensure that it does, regardless of the order you write them in your binding attributes.

Backward compatibility

As always, we’ve taken back-compat very seriously. Knockout v3.0.0 is intended to be fully backward-compatibile with applications built for KO 2.x with one necessary exception:

  • v2.x’s behavior about dependencies between bindings (described in the section about “Independent and ordered bindings” above), is an undocumented internal implementation detail so hopefully you aren’t relying on it. But if you are relying on that then obviously you will see a change of behavior because bindings are independent in v3 by design. You’ll need to stop relying on cross-binding dependencies, which by the way will make your code much cleaner and easier to understand.

Please try v3.0.0 beta with your apps, and let us know if you discover any unexpected changes of behavior. That’s what the beta is for :) .

Credits

As always, big thanks to the KO community and core team for the work involved in producing this. In particular, most of the v3 binding enhancements were designed and implemented by Michael Best in Hawaii. The migration of specs to Jasmine was led by Chris Price in Newcastle. You can thank Ryan Niemeyer who wrote a large portion of the new docs in Wisconsin. Numerous fixes came from Matteo Pagliazzi in Italy. Lots of other people helped too – see GitHub for the full log!

READ NEXT

Knockout-ES5: a plugin to simplify your syntax

Knockout-ES5 is a plugin for Knockout.js that lets you use simpler and more natural syntax in your model code and bindings. For example, you can replace this:

Published May 20, 2013