DurandalJS continues to make dramatic improvements under the direction of lead architect Rob Eisenberg. The framework is easy to pick up since the API is small, well designed, fully featured, and uses technologies familiar to many JavaScript developers, like jQuery, Knockout, and RequireJS.
I’ve been working with Durandal 2.0.1 and my favorite feature, by far, is the observable plugin which allows binding to plain JavaScript objects.
When creating the application, I only need to tell Durandal to use the observable plugin.
define(function(require) { var app = require("durandal/app"); app.configurePlugins({ observable: true // <- }); app.start().then(function() { app.setRoot("{viewModelName}", "entrance"); }); });
And now all my view models can be plain, simple objects.
define(function(require) { var dataService = require("data/movieData"); var viewModel = { movies: [], activate: function() { dataService.getAll().then(function(newMovies) { viewModel.movies = newMovies; }); } }; return viewModel; });
At the core of the observable plugin is Object.defineProperty. This ES5 API requires a compatible browser, but fortunately even IE9 has support. The defineProperty method can build a property with get and set logic, as in the following example.
var person = {}; var propertyDefinition = function(value) { var get = function(){ return value; }; var set = function(newValue) { if(value != newValue) { value = newValue; console.log("Value changed to " + value); } }; return { configurable: true, enumerable: true, get: get, set: set }; }; Object.defineProperty( person, "firstName", propertyDefinition() ); person.firstName = "Scott"; person.firstName = "Allen"; console.log(person.firstName);
With Durandal, you never have to worry about using defineProperty directly. Durandal’s observable plugin provides an API to convert all the properties of an object into Knockout compatible observables using defineProperty.
define(function(require){ var observable = require("durandal/plugins/observable"); var person = { firstName: "Scott", lastName: "Allen" }; observable.convertObject(person); // can still use properties as properties instead of as functions person.firstName = "Ethan"; console.log(person.firstName); });
If we look at the object in the debugger, we’ll see the following.
But even the above code is something you don’t need to write, because Durandal will automatically convert view models into observable objects ready for 2 way data binding before bindings are applied. There’s a lot to be said for frameworks that care about making things easy for the developer.