Knock Me Out

Thoughts, ideas, and discussion about Knockout.js

Knockout.js 2.3.0 and 3.0.0 Beta Are Out

| Comments

Just a brief note that Knockout 2.3.0 is now available. Additionally, there is a beta release of Knockout 3.0.0 available here. Steve Sanderson has a great post highlighting the features/fixes in 2.3.0 and the changes in 3.0.0 beta. I look forward to writing more about 3.0 changes in the coming months.

2.3.0 contains a ton of fixes and improvements. Here is a copy of the 2.3.0 release notes:

Features:

  • hasfocus renamed to hasFocus (hasfocus will still continue to work as well)
  • name parameter of template can accept an observable
  • ko.unwrap added as substitute for ko.utils.unwrapObservable
  • options binding uses same technique as foreach to avoid unnecessary re-rendering
  • optionsAfterRender callback added to allow for custom processing of the added options
  • optionsCaption will display a blank caption if the value is an empty string

Bugs fixed:

  • hasfocus: requires two Tab presses to blur (and related issues) in Chrome; throws error in IE9 on initial binding
  • Error when you try to inline knockout because of </script> string
  • If first node in string template has a binding, the bindings in the template won’t get updated
  • selectedOptions doesn’t update non-observable properties
  • css won’t accept class names with special characters
  • Applying binding twice to the same nodes fails in strange ways (now it fails with an obvious error message)
  • Two-way bindings overwrite a read-only computed property with a plain value
  • Empty template throws an error with jQuery 1.8+
  • observableArray can be initialized with non-array values
  • Event binding init fails if Object.prototype is extended (fixed all for...in loops)
  • Calling ko.isSubscribable with null or undefined causes an error
  • Binding to null or undefined causes an error
  • Memory leak in IE 7, 8 and 9 from event handlers
  • options binding causes error in IE8+ in compatibility mode
  • value binding on select doesn’t match null with caption option
  • Invalid element in string template can cause a binding error
  • Conditionally included select gets close to zero width in IE7-8
  • ko.toJS treats Number, String and Boolean instances as objects
  • value binding misses some updates (1 -> "+1")
  • Exception in ko.computed read function kills the computed
  • Error if spaces around = in data-bind attribute in string template

Maintenance:

  • Port tests to Jasmine
  • Support Node.js
  • Remove build output files and Windows build scripts
  • Build script runs tests using build output (using PhantomJS and Node.js)
  • Use faster string trim function
  • Add automated multi-browser testing using Testling-CI

Knockout.js Troubleshooting Strategies

| Comments

This post contains a number of tips, tricks, and strategies that I have used over the last couple of years to debug Knockout applications. Feel free to share some of your own tips in the comments or suggest other areas that you would like to see discussed.

Binding issues

The most common errors encountered in Knockout typically center around incorrect or invalid bindings. Here are several different ways that you can diagnose and understand the context of your issue.

The classic “pre” tag

One of the main debugging tasks is to determine what data is being used to bind against a certain element. The quick-and-dirty way that I have traditionally accompished this is by creating a “pre” tag that outputs the particular data context that is in question.

Knockout includes a helper function called ko.toJSON, which first creates a clean JavaScript object that has all observables/computeds turned into plain values and then uses JSON.stringify to turn it into a JSON string. You would apply this to a “pre” tag like:

1
    <pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

As of KO 2.1, the second and third arguments are passed through to JSON.stringify with the third argument controlling the indentation to produce nicely formatted output. Prior to KO 2.1, you could still do this by using JSON.stringify(ko.toJS($data), null, 2). You can use this technique to look at specific properties or use the special context variables like $data, $parent, or $root. This will give you output like:

{
  "title": "Some items",
  "items": [
    {
      "description": "one",
      "price": 0
    },
    {
      "description": "two",
      "price": 0
    },
    {
      "description": "three",
      "price": 0
    }
  ],
  "titleUpper": "SOME ITEMS"
}

Lazy? Then just console.log it

Does that “pre” tag look like too much work? An even easier and more direct solution is to simply put a console.log in your binding string. The binding string is parsed into a JavaScript object, so code that you place in it will be executed. In addition, you can also put bindings that don’t exist into your binding string. This is because bindings can be used as options in other bindings (think optionsText or optionsValue), so KO does not throw an exception when it finds an undefined binding handler. This means that you can simply do:

1
    <input data-bind="blah: console.log($data), value: description" />

The block above will output your data to the console just before encountering a typo in the description property. You may even want to wrap your data in a call to ko.toJS or ko.toJSON depending on how you want the output to appear in the console.

Update: in KO 3.0, a binding with no actual handler, will no longer get executed. You would need to use an actual binding like the custom one described below or even something harmless like the built-in uniqueName binding.

Extensions / bookmarklets

There are several great community-created solutions for doing this type of investigation as well:

  • Knockout Context Debugger Chrome extension - adds a pane to the Chrome dev tools that allows you to see the context associated with a specific element. Update: the latest version adds some nice tracing functionality as well. Created by Tim Stuyckens.
  • Knockout Glimpse plugin - Glimpse is a powerful debugging tool for ASP.NET. Aaron Powell created an excellent Knockout plugin for it.
  • Bowtie - a bookmarklet by Max Pollack that lets you inspect the context associated with bindings and add watch values. Note - it does assume that the page includes jQuery.
  • Knockout-debug - a bookmarklet by James Smith that gives a nice display of your view model.

Performance testing - how often is a binding firing?

Sometimes an interesting thing to explore/investigate is how often a certain binding is being triggered and with what values. I like to use a custom binding for this purpose.

1
2
3
4
5
6
7
8
9
10
11
12
13
    ko.bindingHandlers.logger = {
        update: function(element, valueAccessor, allBindings) {
            //store a counter with this element
            var count = ko.utils.domData.get(element, "_ko_logger") || 0,
                data = ko.toJS(valueAccessor() || allBindings());

            ko.utils.domData.set(element, "_ko_logger", ++count);

            if (window.console && console.log) {
                console.log(count, element, data);
            }
        }
    };

This will show you a count of how many times the bindings on this element have been fired. You can either pass in a value to log or it will log the values provided to all bindings on that element. You may want to include a timestamp as well, depending on your needs. There are many times where this will open your eyes to a lot of unnecessary work happening in your UI. It may be from pushing again and again to an observableArray or maybe a case where throttling would be appropriate. For example, you might place this on an element like:

1
    <input data-bind="logger: description, value: description, enable: isEditable" />

and expect output like:

 1 <input.../> "Robert"
 2 <input.../> "Bob"
 3 <input.../> "Bobby"
 4 <input.../> "Rob"
 

Just a note that in the KO 3.0 (almost in beta), each binding on an element will be fired independently, as opposed to now where all bindings fire together. When KO 3.0 is released, you would want to use a binding like this with that in mind and likely only pass the specific dependencies that you are interested in logging.

Undefined properties

Another common source of binding issues is undefined properties. Here is a quick tip for handling scenarios where a property is missing and it will not be added later. This is not specifically a debugging tip, but it can help you avoid potential binding issues without much fuss.

For example, this would cause an error (if myMissingProperty is missing):

1
    <span data-bind="text: myMissingProperty"></span>

However, this will bind properly against undefined:

1
    <span data-bind="text: $data.myMissingProperty"></span>

In JavaScript it is an error to attempt to retrieve the value of a variable that is not defined, but it is fine to access an undefined property off of another object. So, while myMissingProperty and $data.myMissingProperty are equivalent, you can avoid the “variable is not defined” errors by referencing the property off of its parent object ($data).

Catching exceptions using a custom binding provider

Errors in bindings are inevitable in a Knockout application. Many of the techniques described in the first section can help you understand the context around your binding. There is another option that can also help you track and log problems in your bindings. A custom binding provider provides a nice extensibility point for trapping these exceptions.

For example, a simple “wrapper” binding provider might look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    (function() {
      var existing = ko.bindingProvider.instance;

        ko.bindingProvider.instance = {
            nodeHasBindings: existing.nodeHasBindings,
            getBindings: function(node, bindingContext) {
                var bindings;
                try {
                   bindings = existing.getBindings(node, bindingContext);
                }
                catch (ex) {
                   if (window.console and console.log) {
                       console.log("binding error", ex.message, node, bindingContext);
                   }
                }

                return bindings;
            }
        };

    })();

Now, binding exceptions will be caught and logged with the error message, the element, and the binding context (contains $data, $parent, etc.). A binding provider can also be a useful tool to log and diagnose the amount of times that bindings are being hit.

View Model issues

Binding issues seem to be the most common source of errors in Knockout, but there are still errors/bugs on the view model side as well. Here are a few ways to instrument and control your view model code.

Manul subscriptions for logging

A basic technique to help understand how things are being triggered in your view model is to create manual subscriptions to your observables or computeds to log the values. These subscriptions do not create dependencies of their own, so you can freely log individual values or the entire object. You can do this for observables, computeds, and observableArrays.

1
2
3
4
5
6
7
    this.firstName = ko.observable();
    this.firstName.triggeredCount = 0;
    this.firstName.subscribe(function(newValue) {
        if (window.console && console.log) {
            console.log(++this.triggeredCount, "firstName triggered with new value", newValue);
        }
    });

You could format the message to include whatever information is relevant to you. It would also be easy enough to create an extension to add this type of tracking to any observable/computed:

1
2
3
4
5
6
7
8
9
10
    ko.subscribable.fn.logIt = function(name) {
        this.triggeredCount = 0;
        this.subscribe(function(newValue) {
            if (window.console && console.log) {
                console.log(++this.triggeredCount, name + " triggered with new value", newValue);
            }
        }, this);

        return this;
    };

Since the extension returns this, you can chain it onto an observable/computed during creation like:

1
   this.firstName = ko.observable(first).logIt(this.username + " firstName");

In this case, I chose to include the username to ensure that it is outputting a unique value in the case that I have a collection of objects that each have a firstName observable. The output would look something like:

1 "bob1234 firstName triggered with new value" "Robert"
2 "bob1234 firstName triggered with new value" "Bob"
3 "bob1234 firstName triggered with new value" "Bobby"
4 "bob1234 firstName triggered with new value" "Rob"

The value of “this”

Issues with the value of this is one of the most common challenges encountered when starting out with Knockout. Whenever you are binding to an event (click / event binding) and are using a function off of another context (like $parent or $root), you will generally need to worry about the context, as Knockout executes these handlers using the current data as the value of this.

There are several ways to ensure that you have the appropriate context:

1- you can use .bind to create a new function that is always bound to a specific context from within your view model. If the browser does not support bind natively, then Knockout adds a shim for it.

1
2
3
  this.removeItem = function(item) {
      this.items.remove(item);
  }.bind(this);

or if your function lives on the prototype, you would have to create a bound version on each instance (not ideal) like:

1
  this.removeItem = this.removeItem.bind(this);

2- you can create a variable in your view model that corresponds to the current instance (var self = this;) and always use self rather than this in your handlers. This technique is convenient, but does not lend itself to placing functions on a prototype object or adding functions through mix-ins, as these functions need to access the instance through the value of this (unless bound like in #1).

1
2
3
4
5
 var self = this;

  this.removeItem = function(item) {
     self.items.remove(item);
  };

3- you can even use .bind in the binding string, depending on how comfortable you are with seeing it in your markup. This would look like:

1
    <button data-bind="click: $parent.removeItem.bind($parent)">Remove Item</button>

Similarly, you could create a simple custom binding that wraps the event binding and takes in a handler and a context like data-bind="clickWithContext: { action: $parent.removeItem, context: $parent }".

4- the way that I personally handle this now is to use my delegated events plugin, which will do event delegation and as a by-product is able to automatically call the method off of the object that owns it. This also makes it convenient/practical to place your functions on the prototype of your object. With this plugin, the above sample would simply look like:

1
    <button data-click="removeItem">Remove Item</button>

I have found that this removes the vast majority of the context binding concerns that I have in my viewmodel code.

Using the console

One of my favorite ways to debug/investigate a Knockout app is to use the browser’s debugging console. If your view model is well written, you can generally control your entire application from the console. Recently, I ran a data conversion involving hundreds of records from the debugging console by loading the appropriate data, looping through each record to manipulate any observables that needed updating, and saving each record back to the database. This may not always be the best idea, but it was the most practical and efficient way for me to accomplish the conversion for my scenario.

Accessing your data

The first step is getting a reference to your data from the console. If your app is exposed globally, perhaps under a specific namespace, then you are already good to go. However, even if you call ko.applyBindings without your view model being available globally, you can still easily get at your data. Knockout includes ko.dataFor and ko.contextFor helper methods that given an element tell you the data/context that was available to the element during binding. For example, to get your overall view model, you may start with something like this in the console:

1
    var data = ko.dataFor(document.body);

Now you have access to your overall view model (if you simply called ko.applyBindings without specifying a specific root element). With access to that view model, you can call methods, set observable values, and log/inspect specific objects.

Making logging a bit smarter

Anyone that has done debugging in Knockout has likely done a console.log on an observable or computed directly at some point and found some less than useful output like:

1
function d(){if(0<arguments.length){if(!d.equalityComparer||!d.equalityComparer(c,arguments[0]))d.H(),c=arguments[0],d.G();return this}b.r.Wa(d);return c}

One way to improve this output is to add a toString function to the various types. I like to show the name of the type (like observable or computed) and the current value. This helps you quickly understand that it is indeed a KO object, which type it is, and the latest value. This might look like:

1
2
3
4
5
6
7
    ko.observable.fn.toString = function() {
        return "observable: " + ko.toJSON(this(), null, 2);
    };

    ko.computed.fn.toString = function() {
        return "computed: " + ko.toJSON(this(), null, 2);
    };

The output in the Chrome console would now look like:

observable: "Bob"
computed: "Bob Smith"
observable: "Jones"
computed: "Bob Jones"

Note that not all browsers respect the toString function, but it certainly helps with Chrome. Also, observableArrays are a bit harder to handle. Chrome sees that the observableArray (function) has both a length and a splice method and assumes that it is an array. Adding a toString function is not effective in this case, unless you delete the splice function from observableArrays.

Final notes

  • Debugging Knockout core - When you encounter exceptions in your Knockout application, I would not recommend trying to debug the Knockout core library code as your first choice. It is almost always more effective and efficient to isolate the origin of the issue in your application code first and try to simplify the reproduction of that issue. In my experience, the main situation where stepping into Knockout core is potentially a good choice is if you are truly seeing inconsistent behavior between browsers. Knockout core can be challenging to step through and follow, so if you do find yourself debugging into the core library, a good place to start is within the binding handlers themselves.

  • Be careful with logging - if you add logging or instrumentation to your code, be mindful of how this logging may contribute to the dependencies of your computeds/bindings. For example, if you logged ko.toJSON($root) in a computed you would gain a dependency on all observables in the structure. Additionally, if you have a large view model, be aware of the potential performance impact of frequently converting large object graphs to JSON and logging or displaying the result. Throttling may help in that scenario.

  • console.log format - the console.log calls in the snippets are just samples. I understand that some browers don’t support passing multiple arguments to console.log and some do not let you navigate object hierarchies. If you need to do this logging in a variety of browers, then make sure that you build suitable output. The normal case where I am doing logging is temporarily in Chrome during development.

Working With AMD Modules in Knockout.js

| Comments

After being a bit resistant at first, I have happily moved to using require.js to manage dependencies in most of the Knockout.js applications that I have written in the last year or so. With each application, I have tried a number of patterns to make it easier to work with AMD (Asynchronous Module Definition) modules. Recently, I decided to formalize some of these patterns into a lightweight plugin that makes it simple to bind against modules and pull in templates that live in external files.

The result is this library: knockout-amd-helpers

Why require.js and AMD modules

Breaking an application down into small, decoupled modules is a pattern that works well when done right. Creating modules in JavaScript is often accomplished by using various namespacing patterns. As an application grows though, it is easy to lose sight of the individual dependencies of each module and eventually maintaining the order that all of your scripts need to be loaded in becomes a burden as well. AMD module loaders can help with these issues.

There are plenty of good resources that help explain require.js, dependency management, and AMD modules. Here are a few good ones:

  • The require.js documentation on AMD modules.
  • Our documentation on using Knockout with require.js.
  • My co-worker Jonathan Creamer’s tutorial on using Knockout.js in large-scale applications. He also recently did a presentation for dotnetConf that can be found here on using require.js and using it with ASP.NET MVC.
  • While require.js is the most mentioned option in this category, there are others including the excellent curl.js.

A few pain points

When developing Knockout applications using require.js, there are a couple of situations that out-of-the-box still seemed less than perfect to me.

1- After breaking down your application into specific modules, it is unfortunate to have to include all of your markup on a single page. There are server-side solutions to pull in partials for your templates, but that still results in a page that contains all of your markup from the start. There is also the external template engine, which works well, but is not designed to leverage the capabilities of the AMD loader libraries (like optimization/bundling).

2- Dynamically requesting and binding against modules is not trivial. Normally, you would build a main “App” view model that contains all of the sub-modules that you want to bind against. It would be nice though to be able to dynamically pull in modules or use modules as reusable components in an app under any context.

Looking at potential solutions

Based on some of the different approaches that I have used in the past, I created the knockout-amd-helpers plugin to hopefully help ease these issues.

An AMD compatible template engine

The first feature of the plugin is to use one of Knockout’s extensibility points to replace the default template engine with one that is able to load named templates using the AMD loader’s text plugin.

I used the template sources extensibility point that I discussed here. When a named template is requested, it first checks to see if there is a script tag with the specified id (the default engine actually will grab any element with that id) and if not uses the text plugin to require the template. This will asynchronously load the template (unless it has already been loaded or is bundled and already available on the client). The template source uses an observable that triggers the template binding to update when the template is available.

For example, when using a binding like:

1
    <ul data-bind="template: { name: 'itemView', foreach: items }"></ul>

If there is no script tag with an id of itemView, it will attempt to load the template. The engine uses a default path of templates and a default suffix of .tmpl.html. So, it would look for the template at templates/itemView.tmpl.html. The default path and suffix can be configured and you can also pass a more specific path in for the name (sub/path/itemView).

A module binding

This updated template engine now helps keep your templates as modular as your view models, but it still would be nice to easily pull modules into an application without using a top-level view model that needs to contain everything that you might want to bind against.

To help with this situation, the plugin includes a module binding, which offers a flexible way to dynamically pull a module into your markup. Here is a basic example:

1
    <nav data-bind="module: 'navigation'"></div>

This will require a navigation module (the base directory can be configured as well). If the main element had children, then it would use them as an inline/anonymous template. However, in this case, since the element does not have children, it will use navigation as the template name and follow the template engine’s rules for pulling in the template.

After the loading the module it will follow a few rules for deciding what data to bind against:

  1. If the module returns a function, then it will create a new instance
  2. If the module returns an object, then it will, by default, call an initialize function on the object (if it exists) and either use the result of the function or the original object if there is not a return value.

This gives you the flexibility of either constructing a new object, using an existing object, or calling a function that returns some object to bind against.

The module binding has a number of options that you can pass in as well. Here is an example passing all of the options:

1
2
    <div data-bind="module: { name: 'one', data: initialData, template: 'oneTmpl',
                              initializer: 'createItem', afterRender: myCallback }"></div>

These options let you do things like customize the template to use, specify data to pass into the constructor or initializer, define the name of the function to call, and pass an afterRender function through to the template binding.

With this binding, it is possible to call ko.applyBindings({}) and build your application strictly using the module binding. A module binding can be nested inside other module bindings and you can also use observables to dynamically specify your module.

Communicating between modules

When building an app using this structure, it would be less than ideal to rely on $root or $parent calls within the markup to communicate between modules. This can potentially couple your module to only working within a certain context. While this can certanily work, a better solution may be to use some type of messaging to communicate between the modules.

I have a library called knockout-postbox that adds a ko.postbox object and some observable extensions that make it easy to publish values on a topic and update an observable based on a subscription to a topic.

For example, in a module that defines the main content, you could have an observable like:

1
   this.sectionName = ko.observable().subscribeTo("navigation.current");

Then, in the navigation module, publish on that topic like:

1
   this.selectedNavItem = ko.observable().publishOn("navigation.current");

The postbox library supports a number of options that control how the publish/subscribe process works, but if you are looking for a stand-alone library that supports a number of additional features (channels, wildcards, envelopes), then I would recommend postal.js

Summary

If you are using AMD modules in your Knockout application and are looking for a lightweight and simple, but flexible way to bind against templates and modules, then check out this new library. It has been tested with both require.js and curl.js. I would be happy to help support any other AMD loaders, if there is interest. Please check out the README on the repository for additional documentation. I also plan to work on a better example, as time permits.

Joining appendTo

| Comments

Just a quick note that I joined appendTo as a senior JavaScript engineer at the beginning of March. I am really excited to work with a great group of talented people and to get a chance to work on a wide variety of web development projects. I am especially eager to use some new technologies/libraries to solve real problems and can’t wait to gain new perspectives on ways to improve or build on top of Knockout.

If you are looking for help with a significant Knockout project (or any other front-end technology), then I would encourage you to contact appendTo and maybe we could have the chance to work together. For general KO questions or if you are looking for help on a project that only requires a small time investment, feel free to contact me directly.

Tekpub Refactoring Knockout.js Screencast

| Comments

Recently, I had the chance to do some pair programming with Rob Conery to refactor a Knockout-based shopping cart for a Tekpub full throttle video. Rob has had a love/hate relationship with Knockout over the years and I have had several discussions with him in the past trying to work through some of his concerns.

He recently asked me to take a look at a Knockout-based shopping cart that he had written for another video. The code was working just fine, but as I dug into it, I started jotting down a LOT of notes. I ended up formatting them in markdown and sent them Rob’s way. He thought that it would be a good idea to record a screencast to really dig into those notes.

Here is a trailer for the screencast:

I personally have had a Tekpub subscription for around two years and definitely recommend the service. They are really putting out some great content lately and have a well-done Knockout series.

Update: here is a link to the notes that I sent Rob.