AngularJS:在多种资源中重用控制器的最佳实践 [英] AngularJS: Best practices for reusing controller across several resources

查看:41
本文介绍了AngularJS:在多种资源中重用控制器的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几个简单的REST资源(人,房屋等),通常实现为:

I have several simple REST resources (People, Houses, etc.), typically implemented as:

angular
  .module('People')
  .factory('Person', ['$resource', function($resource) {
    return $resource('/api/people/:id', {id: '@id'}
   );
 }]);

每种类型的资源都有一个查看"页面和编辑"页面.但是,每种资源的控制器中的功能基本相同.例如,View控制器始终按以下方式实现:

Each type of resource has a View page and an Edit page. But the functionality in the controllers for each type of resource is largely the same. For instance, the View controller is always implemented as follows:

angular
  .module('People')
  .controller('PersonCtrl', ['$scope', '$routeParams', '$location', 'Person', function ($scope, $routeParams, $location, Person) {

    // load the person
    $scope.person = Person.get({id: $routeParams.id});

    // edit this person
    $scope.edit = function() {
        $location.path($location.path() + '/edit');
    };
}]);

编辑"控制器始终是这样的:

The Edit controller is always something like this:

angular
  .module('People')
  .controller('PersonEditCtrl', ['$scope', '$routeParams', '$location', 'Person',
    function($scope, $routeParams, $location, Person) {

    // edit mode!
    $scope.editMode = true;

    // get the person
    $scope.person = Person.get({id: $routeParams.id});

    // delete this person
    $scope.delete = function() {
        if (window.confirm('Are you sure you wish to delete ' + $scope.person.name + '?'))     {
            Person.delete({id: $routeParams.id}, function() {
                $location.path('/people');
            });
        }
    };

    $scope.save = function() {
        Person.update($scope.person);
        $location.path('/people/' + $routeParams.id);
    };

}
]);

使控制器干燥的最佳方法是什么,以便我可以将相同的代码重用于任意资源?

What is the best way to DRY up the controllers, so that I can reuse the same code for an arbitrary resource?

推荐答案

我建议为控制器和控制器所需的任何其他资源创建模块.然后只需将该模块注入您的顶级模块即可.

I recommend creating a module for the controller and anything other resources that the controller requires. Then just inject that module into your top level module.

所以:

angular.module('Edit').

controller('EditController', ['$scope', function($scope) {
    ...
}]);

angular.module('People', ['Edit']);
angular.module('Houses', ['Edit']);

原来不是那么简单,对吧?正如您在评论中指出的那样,您还需要包括一些正在编辑的数据的表示形式.这可能会很棘手,因为您试图拥有一个可用于编辑不同类型数据的统一控制器.他们必须具有统一的界面才能正常工作.

Turns out it's not quite that simple, right? As you pointed out in your comment, you also need to include some representation of the data that's being edited. This can get tricky, since you are trying to have a unified controller that can be used for editing different types of data. They must have a unified interface in order for this to work.

免责声明:我绝对不能说这是 Angular最佳实践,但这是我已经实现的.在实践中,需要一些肮脏的技巧,但是我认为对数据结构进行更仔细的设计可以减轻这种情况.以下是我的实现的简化示例,并附有注释.该控制器的目的是在列表中显示不同类型的数据.

Disclaimer: In no way can I claim that this is Angular Best Practice, but this is something that I have implemented. In practice, there were some dirty hacks required, but I think more careful design of the data structures can alleviate this. Below is a simplified example of my implementation, with comments. The purpose of this controller was to display different types of data in lists.

var listModule = angular.module('list', [/*dependencies*/]).

// data in my case is the result of the route resolve.
// if you don't use routing, then you can probably just store the data in the service
controller('ListController', ['$scope', 'service', 'data',
    function($scope, service, data) {
        // whatever your controller needs to do - such as:
        $scope.save = function() {
            service.save($scope.someData).
            then(function(r) {
                // update the UI
            });
        };
    }
]).

// this is the "interface" that your services will implement
// definitely not something you will find in the angular docs, but basic OOP, right?
// since it's a provider you can make it even more reusable with a configuration api
provider('Listable', [
    function() {
        return {
            // optional configuration methods
            setBaseUrl: function(url) {
                this.baseUrl = url;
            },

            // if you aren't familiar with providers, this returns the service
            $get: ['$http',
                function($http) {
                    // access configs
                    var provider = this;

                    // This is the "class" that your services will "extend"
                    // whatever parameters you need
                    // probably best to use some conventions in your server api, to make this simpler
                    function Listable(name, fields) {
                        this.name = name;
                        this.fields = fields;
                        this.baseUrl = provider.baseUrl; // and other configs
                    }

                    // this is the API
                    Listable.prototype.index = function() {
                        return $http({
                            method: 'GET',
                            url: this.baseUrl + this.name // or something
                        });
                    };

                    Listable.prototype.save = function(data) {
                        return $http({
                            method: 'POST',
                            url: this.baseUrl + this.name,
                            data: data
                        });
                    };

                    return Listable;
                }
            ]
        };
    }
]);

这也是保留相关UI组件(如此控制器将使用的指令和过滤器)的方便地方.

This would also be a handly place to keep related UI components like directives and filters that would be used by this controller.

完成后,您可以像这样使用它:

Once that is done, you can use it like this:

angular.module('MyApp', ['list']).

factory('People', ['Listable',
    function(L) {
        var People = new L('people', ['first_name', 'last_name', 'dob']);

        // you can also override methods of listable, or implement things that may be specific to each data type:
        People.create = function() {
            return {
                // some initial Person object
            }
        };

        return People;  // People is a service
    }
]);

尤其是如果您不使用路由,我认为在服务中实现 load 方法以将数据输入控制器将很重要.您不想尝试将UI元素绑定到服务中的数据,因此(在我看来)您应该在每次使用模型时将其加载到模型中.

Especially if you aren't using routing, I think it will be important to implement a load method in the service, to get the data into the controller. You don't want to try and bind UI elements to data in the service, so you should load that into the model any time that it is used (in my opinion).

再次,我不知道此实现是否可以通过 Angular最佳实践考试,但是如果您对DRY(像我一样!)发疯了,那是有可能的.

Again, I do not know if this implementation would pass the Angular Best Practice exam, but if you are nuts about being DRY (like me!), then it is a possibility.

这篇关于AngularJS:在多种资源中重用控制器的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆