Windows 8 applications with Ember.js

I’ve previously talked about how painful platform proliferation and fragmentation is for small startups.   It is an immense burden for us to keep our applications at parity across platforms when we have to implement and test everything 3 times across web, Android, and iOS.   So, as I consider adding a Windows 8 app to the mix, I’ve prioritizing spending some time (out of sheer survival) to experiment on how we can do this in a manner that we can better share common components and logic without stooping to the lowest common denominator.   I want to take full advantage of the Metro UI elements but share as much as possible with our web app.

In parallel, I’ve also been experimenting with ember.js and been very pleased with it.   ember.js itself provides a great separation of concerns in classic MVC style with easy data binding support.  Ember Data provides a very nice persistance layer for REST endpoints.   And Ember Route Manager keeps your app transition logic untangled and efficiently moves your app between view states, only tearing down/building the views that are disappearing/appearing in the new state.

And so, inspired by Windows 8’s addition of a first class HTML5+Javascript development model and the success of LinkedIn’s hybrid mobile application, I dove in and built a skeletal Windows 8 application with ember.js last night that I wanted to share with the community. I think the approach is highly promising – but I’d love feedback on where I ended up.

I’ll walk through the points around Ember Route Manager that might be less clear.  I’d recommend you clone my github project to follow along in Visual Studio:

git clone git@github.com:timfpark/windows8-emberjs.git

The app is structured as a normal Windows 8 HTML5+JS app, with default.html as the entry point for the application.   As a single page app, it pulls in all of the javascript libraries, views, and controllers it’ll need here and initialize the application in main.js.  It also defines all of the Handlebars templates it’ll use as part of the Ember application.   A real world scale application should break these out into individual template files and use require.js for the javascript files, but I’ve included them all inline here for simplicity.

routes.js is where we define how our views all fit together via Ember Route Manager.  This defines a top level view state called ‘desserts’ with two substates called ‘index’ and ‘show’ and an initialState of ‘desserts.index’.   We define views that should  be associated with each state and its important to note that the higher level states will also be included.   So for desserts.index, you get both the view for ‘desserts’ and the view for ‘index.’   You can also add logic for when you enter and exit a view state and handle any setup needed for the view, as we do in the ‘show’ enter function where we load the selected desert for the view.


EmberApp.ContentRouteManager = Ember.RouteManager.extend({
 enableLogging: EmberApp.config.enableRouteLogging,
 initialState: 'desserts.index',

 desserts: Ember.ViewState.create({
   route: 'desserts', // static route
   view: Ember.View.create({ templateName: 'app/templates/desserts/main' }),

   index: Ember.ViewState.create({
     route: 'index', // static route
     view: EmberApp.DessertsIndexView
   }),

   show: Ember.ViewState.create({
     route: 'show/:id', // dynamic route
     view: EmberApp.DessertShowView,
     enter: function(stateManager, transition) {
       this._super(stateManager, transition);
       EmberApp.dessertController.loadDessert(stateManager.params.id);
     }
   })
 })
});

EmberApp.routeManager = EmberApp.ContentRouteManager.create();
EmberApp.routeManager.start();

The views and controllers are typical ember.js, so I won’t dwell on them. One interesting detail is in DessertListViewItem.js.

EmberApp.DessertListViewItem = Ember.View.extend({
    content: {},
    click: function (event) {
        EmberApp.routeManager.set('location', 'desserts/show/' + this.getPath('content.id'));
    }
});

I’m using the event here to transition to the detail view for the selected dessert. To do this, we simply tell the route manager which view state we’d like to end up in and it takes care of transitioning us there in the most efficient manner possible by walking the state tree. This means that in the ‘desserts.index’ -> ‘desserts.show’ transition that the ‘desserts’ view at the top level will not be replaced but only the ‘index’ view for a ‘show’ view.

I’ve kept the sample simple by not bringing Ember Data into the mix but a real app would obviously implement against a store instead of stub data (I wrote a previous entry on how to do that).

Ok, so we have implemented a simple Windows 8 application with Ember.js.  So what?

Back up now and look at the application broadly.   What could be reused by a web application?   The answer is:  a whole heck of a lot.   There is some Windows 8 initialization code in main.js and a real application should take advantage of native Metro UI controls (like WinJS.UI.ListView for our dessert picker) in their templates.  That’s ok — we can isolate those pieces in a metro specific template while reusing the view logic, the controller logic, the model logic, probably a lot of the routing logic, and maybe even much of HTML if we have high CSS-fu.

This isn’t write once, run everywhere.   And it shouldn’t be – we all know that doesn’t work.  You should take advantage of the native elements on a platform to match user expectations of how things work.

But this isn’t “write once, write it all again, maintain it all in parallel” either.   Its genius that Microsoft included HTML+JS in Windows 8.   It makes developing Windows 8 apps cleaner, easier, and more reusable for other platforms while still enabling developers to leverage native UI controls.

Let me know what you think.   I’m happy to add details if you find anything unclear.  Pull requests highly appreciated if you have ideas on how to improve what I’ve started.

2 comments

    • magentadev

      You read my mind! 🙂 I’m just waiting for things to settle down a little bit on ember.js master and then I’ll make the conversion and update the blog post. Of course, I’d love a pull request if anyone gets to it first! 🙂

Leave a comment