保持角度控制器很薄

在这一刻我正在处理巨大的角度SPA应用程序。 我尽量保持我的控制器很薄:

<div ng-controller='HomeController as home'>
   <div ng-repeat='var item in home.items' ng-bind='item' ></div>
   <button ng-click='home.remove(1)' >remove</button>
</div>

function HomeController (homeService){
    var vm = this; //$scope
    vm.items = [1,2,3,4,5];
    vm.remove = remove;

    function remove (id){
        homeService.remove({ items: vm.items, targetId: id });
    }

    //a lot of other logic here
}


angular.module('my').service('homeService', homeService);
function homeService (){
    this.remove = remove;

    function remove (param){
        for(var a = 0; a < param.items.length; a++){
            if(param.items[a] == param.targetId){
                param.items.splice(a, 1);
                break;
            }
        }
    }
}

优点:

  • 逻辑在控制器之外
  • 缺点:

  • 服务更改范围状态
  • 保持控制器精简的方法是什么?


    保持控制器精简的方法是什么?

    我个人喜欢在工厂/服务中保留与应用程序模型相关的任何内容。 因此, remove代码中的item并不会在控制器中定义。 在控制器内部,我会设置对模型的引用,以便可以通过$scope访问任何需要的指令。

    作为一个例子,考虑一个带有一系列实体和方法的模型来添加/删除/查找数组中的实体。 我会首先创建一个工厂,展示我的模型和方法以使用它:

    angular.module('myApp').factory('model', function() {
    
        // private helpers
        var add = function(array, element) {...}
        var remove = function(array, element) {...}
        var find = function(array, id) {...}
    
        return {
            Entity: function(id) {
                this.id = id;
            },
            entities: {
                entities: [],
                find: function(id) {
                    return find(this.entities, id);
                },
                add: function(entity) {
                    add(this.entities, entity);
                },
                remove: function(entity) {
                    remove(this.entities, entity);
                }       
            }
    });
    

    然后将模型传递给我的控制器:

    angular.module('myApp').controller('ctrl', function($scope, model) {
        $scope["model"] = model; // set reference to the model if i have to
        var entity = new model.Entity('foo'); // create a new Entity
        model.entities.add(entity); // add entity to entities
        model.entities.find('foo'); // find entity with id 'foo'
    });
    

    等等


    在我的例子中,我想念的第一件事是指令。 指令是一个强大的Angular工具,它允许您重用代码,封装并在HTML中公开行为。 为了保持控制器精简,您需要将指令和服务中的逻辑分开。 我会写你的例子:(不工作的代码,我写了一些东西来说明分割逻辑的想法)

    // "home"
    <div ng-controller='HomeController as home'>
       <my-item ng-repeat='var item in home.items' ng-bind='item'></my-item>
    </div>
    
    // itemtemplate.html
    <div>
        {{ item.name }}
        <button ng-click='remove()' >remove</button>
    </div>
    
    function HomeController (homeService){
        var vm = this; //$scope
        vm.items = homeService.items;
    
        // The idea here is to make this controller 
        // only needed to load content for this route, 
        // all the other logic should be in the directives and services 
    }
    
    angular.module('my').directive('myItem', funcion(homeService){
        return {
            restrict: 'E',
            templateUrl: 'itemtemplate.html',
            controller: function(scope, element, attrs) {
                scope.remove = function(){
                    homeService.remove(scope.item);
                }
            } 
        }  
    })
    
    angular.module('my').factory('homeService', homeService);
    function homeService (){
    
        var items = [];
    
        return { 
            loadItems: function() {
                items = [... pick the items from server or whatever ...];
            },
    
            remove: function() {
                for(var a = 0; a < this.items.length; a++){
                    if(this.items[a] == this.targetId){
                        this.items.splice(a, 1);
                        break;
                    }
                }
            }
        };
    }
    

    我还将items数组移到了服务中(我也将它改为了工厂,因为我认为服务每次注入都需要实例化,并且需要将这些项保留给所有人),这样可以从其他控制器或指令访问它并控制器不必关心它。


    我更喜欢不仅使用精简控制器,而且还更改控制器本身的控制器状态。

    function Ctrl($scope, Service) {
         var ctrl = this;
         $scope.ctrl = ctrl;
         Service.getData().then(function() {
              ctrl.data = Service.data;
         })
    }
    
    function Service ($http) {
        var data = [];
        this.getData = function() {
             return $http.get().then(function(res) {
                  data = res;
             });
        }  
    }
    

    这种结构导致应用程序数据流被单向导向。 所以我总是很确定数据什么时候会刷新,并且始终可以跟踪数据来自哪里。

    当然我会排除一些例外。 例如,如果您不需要数据持久性(应该在$ destroy上删除数据),我将在控制器中保存状态。

    另外我喜欢将服务分开来查看服务和数据服务,其中视图服务负责视图状态,如详细/列表视图,类等。

    另外我喜欢使用自己的事件总线来避免使用手表表达式和广播/发射

    更重要的是,最有用的是将所有标志移动到$ scope.viewType,$ scope.pageClass等单独的指令。 这将导致代码的极端可读性

    链接地址: http://www.djcxy.com/p/26337.html

    上一篇: Keep angular controller thin

    下一篇: How to prevent hasattr from retrieving the attribute value itself