【问题标题】:How to share common logic between controllers?如何在控制器之间共享通用逻辑?
【发布时间】:2015-08-12 13:13:29
【问题描述】:

我有两个页面和两个控制器在同一个数据集上执行搜索。一个有一个简单的表格来指定搜索条件。另一个允许用户在地图上选择数据(通过选择区域或点击地图上的要素)。

然后,搜索结果会显示在搜索控件下方的数据表中(在同一页面上)。

因此,控制器具有不同的搜索功能,但也有许多共同的行为,即显示网格、分页、重新加载、从网格中批量编辑数据等。

因此,在两个控制器中,有几个功能重复,有时略有不同,有时完全相同。

显示数据的页面部分也是一个共享模板,包含在两个搜索页面上的ng-include

这是一个例子:

$scope.selectAllRows = function(){

    var selectedItems = $scope.searchState.selectedItems;

    angular.forEach($scope.searchState.searchResult.rows, function(row){
        // add only if not already selected
        if(selectedItems.indexOf(row) < 0){
            selectedItems.push(row);
        }
    });

};

此函数选择表中的所有行。绑定到页面上某个按钮的ng-click

还有许多其他类似的函数,它们基本上从$scope 读取一些状态,执行一些逻辑,并将新的东西放回$scope

我想删除这些函数的重复,并在单个代码单元中重新组合常见行为。

注意:我想在这里分享的是行为,而不是数据。这些函数将执行相同的逻辑,但作用域不同。

由于这些确实是演示/UI 的东西,并且需要放在$scope 上,我不认为可以使用服务,因为$scope 是严格控制器的东西,不能注入到服务中。

我正在尝试在不同的文件中定义一个独立的函数,并从两个控制器调用这个函数:

myapp.defineCommonControllerBehaviour = function($scope, someOtherService){
    $scope.selectAlRows = function(){....}

    $scope.someOtherCommonTask = function(){
         someOtherService.doTheTask();
    }

    //etc...
};

//controller 1
myapp.defineCommonBehaviour($scope, someOtherService);

//controller 2
myapp.defineCommonBehaviour($scope, someOtherService);

它可以工作,但不是很优雅,因为它在全局范围内定义了一个函数,在任何 Angular 模块之外。

是否有一种角度原生的方式来实现这一点?或者至少更符合 Angular 架构?

【问题讨论】:

  • 听起来您需要一个基本控制器(根据需要建立通用功能并进行扩展)。对 SO 的搜索显示了几种变体,而谷歌则更适合自己。 (例如,this 只是(众多)示例中的 1 个,并将$scope 传递给基础,我觉得这就是您要寻找的)。
  • 似乎您需要将网格功能移动到指令
  • 不要使用基本控制器,因为您不会避免 $scope 继承,并且基本控制器上的功能不会传递给具有隔离范围的指令。通用功能应该是服务(逻辑)或指令(视图组件)的一部分。

标签: javascript angularjs


【解决方案1】:

我发现有些模式对我的用例很有用。

neutral JS code 都可以用来定义和继承你的控制器(缺少依赖管理和原型继承并不是最好的选择,但是 ES2015 类在这种情况下很有帮助)。

或者可以使用 Angular 依赖管理和store common methods and properties in a service:

myApp.service('baseCtrl', function () {
  this.name = 'base';
  this.getName = function() {
    return this.name;
  };
});

myApp.controller('MainController', ['baseCtrl', function (baseCtrl) {
  angular.extend(this, baseCtrl);
  this.name = 'main';
}]);

有第三方解决方案,例如Classy,为控制器提供了自以为是的继承语法。

$injector$controller 也可用于访问父控制器并继承它,但由于引入了controllerAs 语法,因此无需再搞乱$scope

【讨论】:

    【解决方案2】:

    将常用函数放入commonCtrl的作用域,并在子控制器中访问它们。 Angular 孩子的 scope 继承自父母的 scope

    <div ng-controller='commonCtrl'>
        <div ng-controller='featureOneCtrl'></div>
    </div>
    <div ng-controller='commonCtrl'>
        <div ng-controller='featureTwoCtrl'></div>
    </div>
    

    【讨论】:

      猜你喜欢
      • 2014-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多