I\'m looking at Angular\'s generic factory for CRUD (which I am currently in preference of over using a service):
app.factory(\'dataFactory\', [\'$http\', fu
Personally I like to keep my code DRY and I've found that if you keep a common convention on your server API you can go a very long way with a base factory/repository/class or whatever you want to call it. The way I achieve this in AngularJs is to use a AngularJs factory that returns a base repository class, i.e. the factory returns a javascript class function with prototype definitions and not an object instance, I call it abstractRepository
. Then for each resource I create a concrete repository for that specific resource that prototypically inherits from abstractRepository
, so I inherit all the shared/base features from abstractRepository
and define any resource specific features to the concrete repository.
I think an example will be clearer. Lets assume your server API uses the following URL convention (I'm not a REST purest, so we'll leave the convention up to whatever you want to implement):
GET -> /{resource}?listQueryString // Return resource list
GET -> /{resource}/{id} // Return single resource
GET -> /{resource}/{id}/{resource}view // Return display representation of resource
PUT -> /{resource}/{id} // Update existing resource
POST -> /{resource}/ // Create new resource
etc.
I personally use Restangular so the following example is based on it, but you should be able to easily adapt this to $http
or $resource
.
abstractRepository
app.factory('abstractRepository', [function () {
function abstractRepository(restangular, route) {
this.restangular = restangular;
this.route = route;
}
abstractRepository.prototype = {
getList: function (params) {
return this.restangular.all(this.route).getList(params);
},
get: function (id) {
return this.restangular.one(this.route, id).get();
},
getView: function (id) {
return this.restangular.one(this.route, id).one(this.route + 'view').get();
},
update: function (updatedResource) {
return updatedResource.put();
},
create: function (newResource) {
return this.restangular.all(this.route).post(newResource);
}
// etc.
};
abstractRepository.extend = function (repository) {
repository.prototype = Object.create(abstractRepository.prototype);
repository.prototype.constructor = repository;
};
return abstractRepository;
}]);
Concrete repository, let's use customer as an example:
app.factory('customerRepository', ['Restangular', 'abstractRepository', function (restangular, abstractRepository) {
function customerRepository() {
abstractRepository.call(this, restangular, 'customers');
}
abstractRepository.extend(customerRepository);
return new customerRepository();
}]);
And then in your controller you inject customerRepository
:
app.controller('CustomerController', ['$scope', 'customerRepository', function($scope, customerRepository) {
// Use your customerRepository
}]);
What you'll find if you use this base repository pattern is that most of your CRUD controllers will also share a lot of common code, so I typically create a base CRUD controller that my controllers inherit from using $injector.invoke
, but I'll leave examples of this out as it is out of scope of this question.