Models and Collections in Angular?

Evan Hobbs picture Evan Hobbs · Jun 12, 2014 · Viewed 8.2k times · Source

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

Answer

mpm picture mpm · Jun 12, 2014

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,