Knock Me Out

Thoughts, ideas, and discussion about Knockout.js

Knockout.js 2.2 Is Out Now!

| Comments

Just a quick note that Knockout 2.2 is now available. You can read more about the details of this release in the announcement or Steve Sanderson’s blog post.

Here are a few of my favorite changes:

  • The css binding can either toggle specific classes on and off like (css: { error: hasError, required: isRequired }) or now add one or more classes dynamically like css: someClassOrClasses. This is handy when the class names are dynamic. Previously, you could do something similar with the attr binding against the class attribute, but it would overwrite the class attribute completely. When using the css binding in this way, it will now preserve existing classes and will properly remove any class or classes that were previously added by the binding when the value changes.
  • The if and ifnot bindings now only re-render their contents when the bound value changes between truthy and falsy. This helps to alleviate the performance issue described in the first half of this post.
  • There is a new peek function available on observables and computed observables. This allows you to retrieve its value without creating a dependency. This definitely can be useful when you want tight control over when bindings and other subscriptions are triggered, but I would use caution as it does circumvent the normal dependency tracking mechanism. If you find that you need this functionality, then you probably have a good reason why you don’t want a dependency and would understand what does and doesn’t trigger updates.
  • The foreach binding and the foreach option of the template binding now try to understand if items have been moved and will relocate the content rather than tearing it down and re-rendering it at its new position. This comes with some new callbacks (beforeMove and afterMove).
  • The ko variable is now available from within bindings, even if ko is not a global variable (common in AMD scenarios).

You can download the 2.2 files from here. There were no intentional breaking changes made in 2.2 (unless someone was relying on an existing bug), so if you have any issues with your application not behaving as it did in 2.1, please log an issue here.

Getting the Most Out of Knockout.js Session From Twin Cities Code Camp

| Comments

Last weekend, I was invited to talk about Knockout.js at Twin Cities Code Camp. It was a very enjoyable day, as I saw several great presentations and had a chance to talk to many Knockout users.

I was told that there had been several sessions in the past that touched on Knockout, so for this talk I decided to focus on some tips, tricks, and techniques that can be used to get the most out of Knockout. The topics covered included:

  • Brief introduction to Knockout
  • Getting data in and out
  • Extending Knockout’s structures
  • Custom Bindings
  • Performance tips

There was a small amount of overlap with the session that I did at ThatConference in August, but all of the samples were new for this talk. The project that I used to give the presentation is also described in the ThatConference post and a reference project lives here.

Here is a screencast of the presentation:

Getting the Most Out of Knockout.js - 10/06/2012 - Twin Cities Code Camp

A few clarifications from the presentation:

  • At the end of the “getting data out” part, I had typed var meta instead of this.meta.
  • In the maxLength extender, I used a writeable computed observable. In the write function, I should have written the new value to our observable (original(newValue);), in addition to checking its length.
  • In the enterKey custom binding, you probably would want to return the result of the actual function call, as when you return true from a handler called by the event binding, it will allow the default action to proceed, which can be useful at times.
  • In the modal binding where we add a handler for the hidden event, you may want to check if what you are dealing with can be written to as an observable (is an observable or writeable computed observable) by calling ko.isWriteableObservable. So, we might want to call ko.isWriteableObservable(data) before doing data(null).
  • In the modal binding, the wrappers to the with binding, should really be written with with quoted like return ko.bindingHandlers['with'].init.apply(this, arguments); and return ko.bindingHandlers['with'].update.apply(this, arguments);. In IE < 9 the use of with as a property name will cause an error, as it is a JavaScript keyword.

Participating in the code camp was definitely worth the effort of traveling up to the Twin Cities. I would be happy to hear any type of feedback on the presentation. Photo by @JudahGabriel.

Extending Knockout.js Session From ThatConference

| Comments

I had a wonderful time at ThatConference this week. It was really special to be in a place with so many people that are passionate about the same types of things that I am. I also had the pleasure of giving a talk about Knockout. The session mainly focused on the various extensibility points in Knockout. After reviewing some Knockout basics, I discussed extending observables, creating custom bindings, and the idea of binding providers.

For the presentation, I knew that I wanted to show a lot of code, but I was not too excited about continually flipping between a slide show, an IDE, and a browser. So, I decided to create a slideshow from scratch with Knockout that let me combine all three pieces into a single page app. It was quite a bit of work, but it was a fun experience overall.

Here is a screencast of the presentation:

Extending Knockout.js - 08/14/2012 - ThatConference

For creating the presentation app, I used these libraries:

Here is a repository with a heavily stripped down version of the app that I created for this presentation https://github.com/rniemeyer/SamplePresentation.

The binding provider sample implementation is also available here https://github.com/rniemeyer/knockout-classBindingProvider.

I would love to hear any feedback on the presentation. Also, I was thinking about the possibility of recording some short (< 10 minutes) screencasts on various Knockout topics. Would there be any interest in something like that?

Knockout.js Performance Gotcha #3 - All Bindings Fire Together

| Comments

How bindings are processed

Update: In Knockout 3.0, bindings are now fired independently on a single element, so this is no longer an issue for KO 3.0+.

When using multiple bindings on a single element, it is important to understand how Knockout triggers updates to bindings to avoid potential performance issues. For example, a common binding might look like:

1
<select data-bind="options: choices, value: selectedValue, visible: showChoices"></select>

How are the bindings on this element processed? When Knockout determines that an element has bindings, a computed observable is created to aid in tracking dependencies. Inside the context of this computed observable, Knockout parses the data-bind attribute’s value to determine which bindings to run and the arguments to pass. As the init and update functions for each binding are executed, the computed observable takes care of accumulating dependencies on any observables that have their value accessed.

Here is a simplified flow chart of the binding execution:

There are a couple of important points to understand here:

  • The init function for each binding is only executed once. However, currently this does happen inside the computed observable that was created to track this element’s bindings. This means that you can trigger the binding to run again (only it’s update function) based on a dependency created during initialization. Since, the init function won’t run again, this dependency will likely be dropped on the second execution (unless it was also accessed in the update function).

  • There is currently only one computed observable used to track all of an element’s bindings. This means that the update function for all of an element’s bindings will run again when any of the dependencies are updated.

This is definitely something to consider when writing custom bindings where your update function does a significant amount of work. Whenever bindings are triggered for the element, your update function will run, even if none of its observables were triggered. If possible, it is a good idea to check if you need to do work, before actually executing your update logic.

Common problems with the default bindings

1- A common scenario where this can cause an issue is when using the template binding in conjunction with other bindings. For example, you may attach a visible binding along with a template binding like:

1
<div data-bind="visible: showPlaylist, template: { name: 'playlistTmpl', data: playlist }"></div>

In this case, if showPlaylist is frequently updated, it will cause the template binding to re-render the template again. In some cases, this may not cause a concern (it would just behave like the if binding). However, in a scenario where the template has significant markup and the visible binding’s condition is frequently triggered this can cause an unnecessary performance hit. Note that when using the foreach option or binding, logic is executed to determine if any items were added or removed, so it will cause less of a performance hit in that case.

2- Another place where this can come into play with the default bindings is when using the options and value bindings together. The update function of the options binding rebuilds the list of option tags for the select element. Whenever the value is updated, it will trigger all of the bindings on the element to execute. So, instead of just setting the appropriate value, it will rebuild all of the options and then set the value. If you have a situation where you have a large number of options, then this can cause a performance issue.

Ways to address this concern

1- In some cases, it makes sense to put bindings on separate elements or on a container element. For example, you may be able to move a frequently triggered visible binding to a parent element rather have it coupled with other bindings like the template binding.

1
2
3
<div data-bind="visible: showPlaylist">
    <div data-bind="template: { name: 'playlistTmpl', data: playlist }"></div>
</div>

Here is a sample showing a visible and template binding on the same and different elements:

2- In the case of the options and value bindings, you can choose to build your option elements separately. It would be nice to just use a containerless foreach statement inside of a select element, but Internet Explorer will remove comments that it finds between select and option elements. An alternative would be to use Michael Best’s repeat binding on the option element like:

1
2
3
<select data-bind="value: selectedOption">
    <option data-bind="repeat: {foreach: items, bind: 'attr: { value: $item().id }, text: $item().name'}">
</select>

3- A more advanced way to handle these issues, is to create your own computed observable in the init function to handle updates yourself. Any observables accessed in your computed observable, will not be a dependency of the overall computed observable used to track all of the element’s bindings.

This is a technique that I tend to use by default in any bindings that I write. It is also useful when you want a single binding to accept multiple observable options and you want to respond separately to each one changing (as opposed to using the update function to repond when any observable changes). You can even wrap the existing bindings in this way to create an isolatedOptions binding.

1
2
3
4
5
6
7
8
9
10
11
12
13
ko.bindingHandlers.isolatedOptions = {
    init: function(element, valueAccessor) {
        var args = arguments;
        ko.computed({
            read:  function() {
               ko.utils.unwrapObservable(valueAccessor());
               ko.bindingHandlers.options.update.apply(this, args);
            },
            owner: this,
            disposeWhenNodeIsRemoved: element
        });
    }
};

A few notes on this technique:

  • The idea is that we want to trap our dependencies in our own isolated computed observable.
  • We call the update function of the options binding using .apply with the original arguments that were passed ot the binding.
  • The disposeWhenNodeIsRemoved option ensures that this computed observable will be destroyed if Knockout removes our element, like in a templating scenario.
  • There is one minor issue with using this technique currently: observables that are accessed in the actual binding string are included in the overall computed observable during parsing rather than when you create you call valueAccessor. This means that if your binding contains an expression where you access the observable’s value (text: 'Hello ' + name()) , then it will be tracked in the overall computed observable. This is likely to change in the near future.

Here is a sample that shows using #2 and #3 with options and value bindings: http://jsfiddle.net/rniemeyer/QjVNX/

Future

There has been some thought and work put into running each binding in the context of its own computed observable. Michael Best has this working properly in his Knockout fork. As these changes can be considered breaking, they will likely be carefully implemented over time using an opt-in approach, perhaps until a major version allows us to make some potentially breaking changes. For now, it is wise to keep in mind how your bindings are triggered and how that affects other bindings on the same element.

Using KO’s Native PubSub for Decoupled Synchronization

| Comments

In the previous post, I suggested some ideas for binding against multiple view models in Knockout.js. When working with more than one view model, a common task is deciding how to communicate between the separate components. Creating direct references between them often doesn’t feel right and can lead you down a path where each view model has lost its independence and cannot be used effectively without the other objects.

To handle this situation, we can keep our components loosely coupled by using a messaging system where each view model or component does not need to have direct references to its counterparts. There are several benefits to using this technique:

  • Components remain independent. They can be developed, tested, and used in isolation.
  • Knockout view models and non-KO components can communicate using a common interface without direct knowledge of each other.
  • Components can be safely refactored. Properties can be renamed, moved, and adjusted without worrying about breaking compatibility.

Knockout’s native pub/sub

There are already many libraries and options for providing this type of message bus. One option might be triggering custom events or using great pub/sub libraries like amplify.js or postal.js. While these libraries provide robust capabilities, Knockout itself already has all of the tools to do basic pub/sub communication built-in. This is part of the ko.subscribable type, which has its capabilities added to observables, computed observables, and observableArrays.

Normally, you would not construct a ko.subscribable directly, but it is easy enough to do so:

1
var postbox = new ko.subscribable();

In Knockout 2.0, support was added for topic-based subscriptions to aid in sending out beforeChange notifications. To create a topic-based subscription against our ko.subscribable, we would simply do:

1
2
3
4
5
6
postbox.subscribe(callback, target, topic);

//with some actual code
postbox.subscribe(function(newValue) {
    this.latestTopic(newValue);
}, vm, "mytopic");

To send out a notification on this topic we would do:

1
postbox.notifySubscribers(value, "mytopic");

Now, we can do basic pub/sub messaging using subscribe and notifySubscribers against our mediator, the postbox object. However, whenever I explore integrating a new technique with Knockout, I try to consider how to make it feel as easy and natural as possible.

Extending Observables

A typical scenario for this type of functionality would be that we want to synchronize an observable between view models. This might be a one-way or even a two-way conversation. To make this easy, we can look at extending the ko.subscribable type, which would affect observables, observableArrays, and computed observables.

Suppose that we want to setup an observable to automatically publish on a topic whenever it changes. We would want to set up a manual subscription against that observable and then use notifySubscribers on our postbox.

1
2
3
4
5
6
7
8
9
10
ko.subscribable.fn.publishOn = function(topic) {
    this.subscribe(function(newValue) {
        postbox.notifySubscribers(newValue, topic);
    });

    return this; //support chaining
};

//usage of publishOn
this.myObservable = ko.observable("myValue").publishOn("myTopic");

Now, whenever the observable’s value changes, it will publish a message on the topic.

On the other side, we might want to make it easy for an observable to update itself from messages on a topic. We can use this same concept:

1
2
3
4
5
6
7
8
ko.subscribable.fn.subscribeTo = function(topic) {
    postbox.subscribe(this, null, topic);

    return this;  //support chaining
};

//usage
this.observableFromAnotherVM = ko.observable().subscribeTo("myTopic");

Notice that we can just pass this (the observable) in as the callback to the subscribe function. We know that an observable is a function and that it will have its value set when you pass an argument into the function. So, there is no need to write something like:

1
2
3
4
//no need to add an extra anonymous function like:
postbox.subscribe(function(newValue) {
    this(newValue);
}, this, topic);

Now, our observables can exchange information without direct references to each other. They do need to agree on a topic, but do not have any knowledge about the internals of the other view model or component. We can even mock or simulate the other components in testing scenarios by firing messages.

Potential gotcha: publishing objects

If the new value being published is an object, then we need to be careful, as both sides will have a reference to the same object. If code from multiple view models makes changes to that object, then we are likely no longer as decoupled as we would like. If the object is simply configuration/options passed as an object literal that are not modified, then this seems okay. Otherwise, it is preferable to stick to primitives in the values being published. Another alternative is to use something like ko.toJS to create a deep-copy of the object that is being published, so neither side has the same reference.

A new library: knockout-postbox

I created a small library called knockout-postbox to handle this type of communication. It uses the techniques described above and adds a bit of additional functionality:

  • creates a ko.postbox object with clean subscribe and publish methods that take a topic as the first argument.
  • adds a subscribeTo function to all subscribables (observables, observableArrays, and computed observables). The subscribeTo function also allows you to initialize your observable from the latest published value and allows you to pass a transform function that runs on the incoming values.
  • adds an unsubcribeFrom function to all subscribables that removes subscriptions created by subscribeTo.
  • adds a publishOn function to all subscribables that automatically publishes out new values. The publishOn function also allows you to control whether you want to immediately publish the initial value, and lets you supply an override function (equalityComparer) that allows you to compare the old and new values to determine if the new value should really be published.
  • adds a stopPublishingOn function to all subscribables that removes the subscription that handles the publishOn messages.
  • adds a syncWith function that does both a subscribeTo and a publishOn on the same topic for two-way synchronization.

Project link: https://github.com/rniemeyer/knockout-postbox

Basic sample:

Link to sample on jsFiddle.net

Next post: using this concept to integrate with client-side routing in a way that is natural to Knockout