Javascript – Models and Collections in Angular

angularjsbackbone.jsjavascriptrestangular

I'm coming from Backbone so perhaps my perspective is prejudiced by that but I'm having trouble seeing the best way to model data in Angular. The 2-way data-bind is pretty awesome but past that when I want to have persistent collection and model classes I'm confused.

I'm using to being able to define a collection, say of users, and then being able to call .fetch() whenever I want to update it with new models. As well I can define custom methods on the collection as well as each model.

var users = new UserCollection();
users.fetch();
users.doSomethingCustom()
users.at(0).doSomethingModel();

I've looked at Restangular and ngActiveResource so far and neither one seems to offer the same kind of functionality as I would expect.

Is there something I'm missing or perhaps I'm thinking about this in a non-Angular way?

EDIT: I ended up making my own models/collections very similar to Backbone's if it helps anyone: https://github.com/evanhobbs/angular-models

Best Answer

This is indeed a very interesting question,and I'd like people to think about solutions. In theory,you could stick with Backbone models.It may have a performance cost but.There is no reason it wouldnt work.

Develop your model layer,without thinking about AngularJS.Then you'd have to extend your models and add a listener in your initialize function that would trigger a $rootScope.$apply whenever the model changes,same for any collection you might use.Something like :

/*global angular,Backbone*/
angular.module('ng')
    .value('Backbone', Backbone)
    .factory('AngularModel', function(Backbone, $rootScope) {
        return Backbone.Model.extend({
            initialize: function() {
                this.on('all', function() {
                    if (!$rootScope.$$phase) {
                        $rootScope.$apply();
                    }
                });
            }
        });
    })
    .factory('AngularCollection', function(AngularModel, $rootScope) {
        return Backbone.Collection.extend({
            model: AngularModel,
            initialize: function() {
                this.on('all', function() {
                    if (!$rootScope.$$phase) {
                        $rootScope.$apply();
                    }
                });
            }
        });
    });

function Main($scope, AngularCollection) {
    $scope.collection = new AngularCollection([{
        name: "foo"
    }, {
        name: "bar"
    }, {
        name: "baz"
    }]);
    $scope.addModel = function(model) {
        $scope.collection.add(model);
    };

}

and the view

<body ng-app ng-controller="Main">
    <div ng-repeat="model in collection.models">{{model.get('name')}}</div>
    <form name="model_form" ng-submit="addModel(model)">
        <fieldset>
            <legend>Add model</legend>
            <label for="">Name</label>
            <input type="text" ng-model="model.name" />
            <input type="submit" />
        </fieldset>

    </form>
</body>

Some DEMO HERE

Now in my opinion,AngularJS works better with raw js hashes.But If you need to port something to AngularJS from Backbone,it can be a solution if already have a strong model layer.

EDIT:it might work without the expensive $rootScope.$apply,