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:
- Improved security by avoiding the use of
eval
. This provides an extra layer of protection against XSS attacks by allowing your site to implement a strict Content Security Policy. - Built as ES modules via esbuild. That means it can be
import
-ed into modern JavaScript/TypeScript projects to take advantage of features like tree-shaking to minimize code size. - …
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
- Generated API docs coming soon™
- Knockout Reference is still mostly accurate for TKO