Is it possible and in good form to reuse the same data factory in Angular?

后端 未结 1 1957
挽巷
挽巷 2021-01-01 05:09

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         


        
相关标签:
1条回答
  • 2021-01-01 05:43

    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.

    0 讨论(0)
提交回复
热议问题