Site Meter
 
 

Knockout 2.1.0 released

Last night we released version 2.1.0 of knockout.js. This brings a whole bundle of added functionality and performance improvements. For a more detailed rundown of what’s new, see Ryan Niemeyer’s blog post.

With this release we welcome new core team member Michael Best, who implemented a lot of the 2.1.0 goodness. One of my favourite new features is the $index context variable. Here’s a short usage example:

The cool thing is that $index is an observable and is updated automatically as you add or remove items in any collection bound to a foreach (and so your UI will update to match). Impressively, Michael was able to add this new functionality while simultaneously improving the performance of foreach whether or not you are using $index!

We also benefited from pull requests, issue reports, and feature suggestions from many others in the community. Special thanks to neonstalwart and mtscout6 for not only implementing AMD module loader support and putting up with a lot of questions from me, but even including full documentation pages in their pull request – flawless OSS etiquette!

Again, if you want to know more about what’s new in KO 2.1.0, head on over to Ryan’s post for a full rundown.

Single Page Application packages and samples

This post is for you if you saw my ASP.NET Single Page Applications presentation at recent conferences and would like to try out the code for yourself.

Getting the post-beta tools update, and running the scaffolder

First, make sure you have ASP.NET MVC 4 Beta. Then if you want to scaffold up a simple data-editing SPA,

  • Create a new MVC 4 project. Choose the Single Page Application subtemplate.
  • Once you’ve created the new project, pop open NuGet package console (View > Other Windows > Package Manager Console), and install the latest scaffolder templates as folllows:
Install-Package SinglePageApplication.CSharp

Or, if you’re using Visual Basic instead of C#, install the VB package instead:

Install-Package SinglePageApplication.VisualBasic

Don’t skip this step, otherwise you’ll be using the old beta SPA templates and the result will be much less interesting.

Note that Visual Studio may give a false compiler error (“The type or namespace name ‘MvcTextTemplateHost’ could not be found”) – you can either just ignore it, or restart Visual Studio to make it go away. This is an unfortunate limitation of the way we’re packaging this post-beta update, and won’t affect the final tooling.

  • Now you can follow the on-screen instructions in /Models/TodoItem.cs to scaffold a simple data-editing SPA. Use the Add Controller dialog as explained in the comments on that file, remembering to build the solution first, and then you can run the app and browse to http://localhost:whateverport/Tasks.

image

If you want to learn what the point of all this is, see http://www.asp.net/single-page-application or watch this presentation.

Getting the DeliveryTracker sample

If you want to see a slightly bigger and more fun app built with the same libraries and architecture, you can get hold of the DeliveryTracker app that I built during the SPA presentation. If you want to see the mobile UI, you’ll want to either use a real mobile to view it, or fake your useragent (instructions for IE or Chrome or Firefox).

image

Note that the source on GitHub doesn’t include the offline support, as that’s still very early in development – the design and functionality is still likely to change significantly.

Knockout 2.0.0 released

Here it is at last! Knockout 2.0.0 contains a huge set of improvements since the 1.2.x line. If you’re using KO already, see below for some of the highlights.

New to all this? Now’s a great time to check it out. Knockout is an MVVM library for JavaScript – it makes rich dynamic web UIs easier and cleaner to build. The best place to start learning is with the interactive tutorials.

What just happened?

Credits go to the many community members who contributed pull requests, bug reports, new documentation, and support during this process. These people include aaronpowell, amonat, antis, aredridel, artiomchi, barkmadley, b-dur, bmac, cburgdorf, develop-me, DomenicDenicola, doodlemoonch, dre2901, drewlesueur, ducka, gigi81, GLuKKi, hunterloftis, ifandelse, joeldart, kmalakoff, lcbarcellos, mbest, mtscout6, neonstalwart, owenssam, Quaternion, rniemeyer, RoyJacobs, schinckel, seanami, SimonBartlett, studgeek, tehsenaus, and tiberiuana – and that’s just those who made recent pull requests (apologies for not tracking everyone who contributed other things). rniemeyer wrote a lot of documentation too.

Why is it called 2.0.0? Why not 1.3.0?

For a long time, we were planning this next version to be called 1.3.0. However,

  • Quite a few community members are keen on adopting SemVer-style versioning. 2.0.0 is a good place to start (expermentally) with that versioning convention.
  • It’s such a big set of core changes that if this doesn’t count as 2.0, I guess nothing ever would…

New features

I’m mostly going to copy and paste the “what’s new” list from my earlier blog post about Knockout 1.3 beta, with a few further updates. Besides these things, there are all the usual bugfixes and performance improvements that you’d expect.

1. Control flow bindings

Previously, if you wanted to display a repeating sequence of UI elements (“foreach”), or have a section of the DOM exist only if some viewmodel condition was true (“if”), you’d need to create an entire template to define that. A bit cumbersome for something so simple and commonplace! Now you can use the new control flow bindings – if, ifnot, with, and foreach – to achieve basic, declarative control flow without the need for a template. This can make your code a lot more elegant and to-the-point.

Here’s an example of using “foreach” and “if”:

Tip: Switch to the “result” tab to see the output

The "with" binding changes the binding context to whatever object you specify. This makes it easy to compose many independent view models together – you have a host model that contains references to its children, and then use "with" to bind different sections of the page to different child models. Example:

Of course, the "if", "ifnot", "foreach", and "with" bindings can all be combined and nested arbitrarily.

2. Containerless control flow

What if you want to set up template-less control flow (as in the above example), but without having to use extra container elements just to hold the "foreach", "if", etc., bindings? In that case, you can use the new comment-based control flow syntax like this:

The comment-based control flow syntax works with the "if", "ifnot", "foreach", "with", and "template" bindings. In a large number of cases, this means you can skip string-based templates and use the binding-based control flows instead, which can run much faster depending on what exactly you’re doing.

3. Access to parent binding contexts

Whether you’re using regular nested templates, or nesting the new control flow blocks, sometimes you want to reference properties that exist at the upper levels of binding. There are four new pseudo-variables that you can use in any binding (inside or outside traditional templates):

  • $data – returns the current item
  • $parent – returns the item from the parent binding context
  • $parents – an array containing all the parent binding contexts. $parents[0] == $parent, then $parents[1] is the level above that, and so on.
  • $root – returns the item at the top level of binding (usually your primary view model)

Example:

4. Cleaner event handling

In most cases, data-bind attributes can be kept clean and elegant. But one rough spot in the past has been event handlers, because to pass parameters, you were generally guided to use function literals. For example:

<button data-bind="click: function() { viewModel.items.remove(this) }">Click me</button>

Many of you rightly pointed out that this is pretty ugly. It’s much nicer if bindings can be kept minimal and declarative! To fix this, KO 2.0 offers two alternative event handling syntaxes, both of which are better.

Firstly, event handlers now receive the current model value as their first parameter. So, you can implement “remove-from-list” as follows, with no inline function literals:

The other option is to use jQuery event delegation to catch events and invoke functions on your viewmodel. This is made possible by the ko.dataFor and ko.contextFor helpers, which tell you which part of your viewmodel a given event relates to. Here’s the preceding example, but now using event delegation:

5. Binding providers (and hence external bindings)

Most KO developers find the default data-bind attributes provide a very convenient, easy-to-maintain way of declaratively associating viewmodels with views. But if you would prefer to store your binding configuration elsewhere, the new binding providers API is an extensiblity point that allows alternative configuration mechanisms to be plugged in.

For example, here’s one possible alternative way that you could configure bindings. Notice the absence of data-bind attributes – I’m using a binding provider to set up the binding configuration in JavaScript:

To be clear, binding providers are a general extensibility mechanism, not any specific configuration format. The above example is just one possible way it can be used to define bindings in JavaScript. I’m looking forward to seeing suggestions from the community about how this extensibility can be used, and for what the most elegant and convenient way of defining bindings might be. I know some of you have already suggested externalising bindings (e.g., Brandon Satrom’s knockout.unobtrusive plugin); this new API will make it easier to implement custom binding mechanisms. Bring on more plugins!

6. Throttling

Note: ko.computed is Knockout 2.0’s new name for ko.dependentObservable – it’s easier to say, type, and explain. This doesn’t affect backward compatibility, though – ko.dependentObservable still works, because it references the same function instance as ko.computed at runtime. You don’t have to change your existing code if you don’t want.

Occasionally, it’s desirable to limit how fast observables and computed observables update. For example, you might be using a ko.computed to invoke Ajax requests whenever a set of observables change. Sometimes you might want to change multiple underlying observables, but only have that ko.computed re-evaluate once, after all the changes (so that it only fires one Ajax request). Effectively, you want a kind of atomic update.

This is now pretty easy to do: you can apply an extender called "throttle" either to observables or to computed observables. For example:

// Will not notify changes faster than once per 500ms 
var myObservable = ko.observable("initial value").extend({ throttle: 500 });
 
// Will not re-evaluate *or* notify changes faster than once per 500ms 
var myComputed = ko.computed(function() { 
    // Evaluation logic goes here, usually referencing other observables 
    return 123;
}).extend({ throttle: 500 });

The way this works is that, when throttled, notifications and evaluations are done asynchronously, and don’t occur at all until they stop being triggered for the specified throttle timeout duration.

In the case of making a computed value only update once even if there are multiple synchronous changes to its dependencies, you can use a very short timeout (for example, 1ms), and then it will re-evaluate as soon as possible after any series of synchronous changes to its dependencies. Example:

Breaking changes

There are two changes that might realistically affect existing 1.2.x application code. Both are for good reasons and are important for the long-term health of the project…

  • Event handlers now receive your model object as their first parameter, and the DOM event object as the second parameter. Previously, they only received the DOM event object as the first parameter. So, if you are using the “click” or “event” bindings and are specifically catching and using the DOM event object, you’ll need to change your handler’s signature from this:

myViewModel.myEventHandler = function(evt) { /* do something with evt */ }

… to this:

myViewModel.myEventHandler = function(data, evt) { /* do something with evt */ }

This will not affect any event handlers that don’t specifically receive and process the “event” parameter. We chose to make this change because it significantly simplifies event handling in the majority of cases. Most developers have been able to upgrade to 2.0.0 beta without changing their applications at all.

  • KO 2.0.0 drops support for very old versions of jquery-tmpl. If you need to use string-based templating (and most often you won’t now that KO 2.0.0 has native control flow bindings), get jquery-tmpl 1.0.0pre. But also consider dropping the string-based templating, and switching to control flow bindings instead, as jquery-tmpl is no longer in active development.

Summary

Try the updated interactive tutorials, update your existing KO applications, have a great Christmas/vacation/newyear Smile