TKO: Technical Knockout

Introduction

TKO is a two-way binding framework for creating dynamic web UIs.

Hello {{name}}!

TKO is the successor to Knockout. Compared to its predecessor, TKO features some notable improvements:

Getting Started

Here’s a full-fledged demo for ye olde TODO app:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Amet consectetur adipiscing elit ut aliquam purus sit amet. Ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at. Ultrices vitae auctor eu augue ut lectus. Sed nisi lacus sed viverra tellus. Nulla malesuada pellentesque elit eget gravida cum sociis. Quis varius quam quisque id diam vel quam elementum. Egestas fringilla phasellus faucibus scelerisque eleifend donec pretium. Metus aliquam eleifend mi in nulla posuere sollicitudin. Lacus luctus accumsan tortor posuere ac ut consequat semper viverra. Nisi lacus sed viverra tellus in. Ultrices sagittis orci a scelerisque purus semper eget. Amet aliquam id diam maecenas ultricies. Viverra orci sagittis eu volutpat odio facilisis mauris sit. Rutrum quisque non tellus orci ac. At varius vel pharetra vel turpis nunc eget. Ac odio tempor orci dapibus ultrices in iaculis nunc. Porttitor lacus luctus accumsan tortor posuere ac ut consequat semper.

Aliquet sagittis id consectetur purus ut faucibus pulvinar elementum. At elementum eu facilisis sed odio morbi quis commodo. Eget magna fermentum iaculis eu. Cursus vitae congue mauris rhoncus aenean vel. Felis eget velit aliquet sagittis id consectetur purus ut faucibus. Tincidunt praesent semper feugiat nibh sed pulvinar proin gravida. Lectus urna duis convallis convallis. In cursus turpis massa tincidunt dui. Odio aenean sed adipiscing diam donec adipiscing tristique risus. Sed lectus vestibulum mattis ullamcorper velit sed. Sapien et ligula ullamcorper malesuada proin libero nunc. Tellus integer feugiat scelerisque varius morbi.

In fermentum et sollicitudin ac orci phasellus. Arcu risus quis varius quam quisque id. Massa id neque aliquam vestibulum morbi blandit cursus risus. Massa vitae tortor condimentum lacinia quis vel eros donec ac. Egestas maecenas pharetra convallis posuere morbi leo. Sodales ut eu sem integer vitae justo eget. Erat nam at lectus urna. Volutpat blandit aliquam etiam erat velit scelerisque in dictum non. Quam pellentesque nec nam aliquam sem et. Pellentesque habitant morbi tristique senectus. At in tellus integer feugiat scelerisque varius morbi enim. Tempor orci dapibus ultrices in.

Migrating from Knockout

The Knockout-compatible build can be used as a drop-in replacement for existing pages that utilize Knockout. There are a few backwards-incompatible changes that may need to be addressed:

➤ Bindings can’t be multi-statement function literals

Unlike KO, because TKO doesn’t use eval for parsing bindings, only single-expression arrow functions are supported in bindings. The KO-compatible build will convert function literals in bindings into an equivalent arrow function, but only if the function body contains exactly one statement. Bindings like:


<button data-bind="click: function() { doX(); doY(); }">
  Do X then Y
</button>
              

…will need to have the function moved into the view model like so:


// view model
this.doXThenY = function () { doX(); doY(); }

// binding
<button data-bind="click: doXThenY">
  Do X then Y
</button>
// …or…
<button data-bind="click: () => doXThenY()">
  Do X then Y
</button>
              

➤ Bindings can’t access the global window scope

To limit the scope of possible XSS attacks, bindings no longer have access to the global window scope by default. Any global objects you want bindings to access should be exposed as an explicit view model property:


// before
<span data-bind="text: location.href"></span>

// after view model
this.pageUrl = window.location.href

// after binding
<span data-bind="text: pageUrl"></span>
              

foreach with as option no longer creates child context

If you provide the as option to a foreach binding, TKO no longer creates a child binding context. This means that any uses of $parent or $parents inside of the loop will need to be updated.


// before
<ol data-bind="foreach: {data: myArray, as: 'foo'}">
  <li data-bind="text: $parent.textForFoo(foo)"></li>
</ol>

// after
<ol data-bind="foreach: {data: myArray, as: 'foo'}">
  <li data-bind="text: textForFoo(foo)"></li>
</ol>
// or
<ol data-bind="foreach: myArray">
  <li data-bind="text: $parent.textForFoo($data)"></li>
</ol>
              

Contributing

Bug reports, pull requests, and discussions are all welcome via the GitHub page.

Reference