onsdag 7 maj 2014

Migrating a Backbone.js application to Angular.js

Today I completed the first part of migrating our Backbone based web app over to Angular.
Our app is fairly complex, built with Backbone.Marionette and require.js. We use backbone.iobind together with socket.io to make sure any user is always viewing the latest data from the backend. We use Backbone.Forms to render html from json. And Backbone.ModelBinder to bind input fields to models. All of the above functionality can be acheived with Angular core + some plugins, but I like to do these sort of tasks with as small steps  as possible. 

My initial goal is to change as little code as possible, keep all of the functionality, while using Angular for routing and dependency injection. 

Step 1: create an Angular app:

yo angular

(In case you don't know what yo means, check out Yeoman here and here)

When you're workin towards a REST backend with Angular, you probably will use either $http or $resource. But you're options don't end with the built in Angular modules or with Angular plugins; you can use whatever library you want. For instance Backbone. This means I can keep our Backbone models and collections, while focusing on getting our views and controllers right.

To acheive this I created an angular service which contains all of the Backbone Models and Collections. I don't really mind having all of them in the same file, since my plan is to gradually remove them and use Angular standards instead.

But until then, this is what my backbone model service looks like now:

angular.module('myAngularApp')
    .service('Restapi', function Restapi() {
this.MyModel = Backbone.Model.extend({ // ... }); }
In the original application I had a lot of logic in views (Region, Composite and ItemViews). For instance: In one view I create a Backbone.Form from a json schema, fetch a Backbone model and bind it to the schema. To make this work with angular I just copied this code into angular controllers instead like this:

angular.module('myAngularApp').
controller('MyCtrl', function(Restapi) {
    $scope.myModel = new Restapi.MyModel({
       id: 123456
    });
    $scope.myModel.fetch({
       success: function() {
 var form = new Backbone.Form({
  model: $scope.myModel,
  schema: someJson
 });
 form.render();
 $('#some-id-to-place-the-form').append(form.el);
     }
});
So this is more or less how I did it, just a lot of copying and pasting the old Backbone code into my newly created Angular project. Now I can continue to remove Backbone, one piece at a time until I no longer need the Backbone dependencies.