从另一个控制器更新ng-repeat上的复杂滤波器

Update complex filter on ng-repeat from another controller

本文关键字:复杂 滤波器 ng-repeat 另一个 控制器 更新      更新时间:2023-09-26

我有两个控制器和一个共享服务。控制器A是该页面的主视图,包含一个填充了数据的ng-repeat。控制器B包含控制器a中ng-repeat的过滤选项,这工作得相当好,下面我有一个基本的剥离示例,说明我是如何使其工作的。

我的问题是:我如何在控制器A中引入更复杂的滤波?我知道我需要用一个函数来做复杂的过滤,这就是问题所在。

angular.module('app').factory('optionService', [/*'stuff'*/, options]);
function options(/*stuff*/){
    var someOption = false;
    var filters = {};
    var service = {
        someOption: someOption,
        filters: filters
    }
    return service;
}
angular.module('app').controller('controllera', ['dataSvc', 'optionService', ctrla]);
function ctrla(dataSvc, optionService){
    var vm = this;
    vm.options = optionService;
    vm.items = dataSvc.getItems();
}
angular.module('app').controller('controllerb', ['optionService', ctrlb]);
function ctrlb(optionService){
    var vm = this;
    vm.options = optionService;
    vm.toggleSomeOption = function(){
        vm.options.someOption = !vm.options.someOption;
        if(vm.options.someOption){
            vm.options.filters.someProperty = 'foo';
        } else {
            delete vm.options.filters['someProperty'];
        }    
    }
}
<div ng-controller="controllera as vm">
    <ul>
        <li ng-repeat="item in vm.items | filter:vm.options.filters">{{item.bar}}</li>
    </ul>
</div>

我已经尝试将过滤方法放入服务,并将其添加为ng-repeat中的过滤器,但当选项更新时它不会触发。

我是否应该使用事件或$rootScope以某种方式通知controllerb中的选项已经更改并且需要更新(例如通过手动注入自定义过滤器并运行该)?

总而言之,我有点困惑如何让这个工作,以及最好的方法。

是的,我认为更新没有发生,因为当ControllerB的范围发生变化时,但angular不知道它应该检查ControllerA的范围。

你可以开始搞乱$scope.$apply()$scope.$digest(),但它们非常丑陋,远远不是"最佳实践"。我更推荐使用$timeout(func, 0),因为这也会导致对作用域的脏检查。所以这个过程:

  • ControllerA在optionService
  • 中注册为某种侦听器
  • ControllerB更新选项。这会触发事件
  • ControllerA接收到一个触发器并调用$timeout()。这样,它的作用域就会知道
  • 的变化。
  • $timeout()立即执行并更新ControllerA
  • 的作用域
  • 更改应该在ng-repeat中可见。

我已经成功地使用$rootScope.$broadcast$scope.$on实现了这一点。

在控制器B中,当选项被选中时(它是一个checkbox),我切换存储在服务中的选项,并广播一个事件来表示选项已被更新。在控制器A中,监听事件,并应用作为依赖项传入的过滤器,并针对复杂的过滤器方法运行,该方法只是一堆if/else(尽管很快将被重构到其他地方)。

angular.module('app').factory('optionService', [/*'stuff'*/, options]);
function options(/*stuff*/){
    var someOption = false;
    var service = {
        someOption: someOption
    }
    return service;
}
angular.module('app').controller('controllera', ['dataSvc', '$scope', 'filterFilter', 'optionService', ctrla]);
function ctrla(dataSvc, optionService){
    var vm = this;
    vm.options = optionService;
    vm.items = dataSvc.getItems();
    vm.filtereditems = [];
    function complexFilter(item){
        if(item.foo === 'bar' && vm.options.someOption){
            return true;
        }
        /* etc etc */
    }
    function runFilter(){
        vm.filtereditems = filterFilter(vm.items, complexFilter);  
    }
    $scope.$on('updated', function(){
        runFilter();
    };
}
angular.module('app').controller('controllerb', ['optionService', '$rootScope', ctrlb]);
function ctrlb(optionService, $rootScope){
    var vm = this;
    vm.options = optionService;
    vm.toggleSomeOption = function(){
        vm.options.someOption = !vm.options.someOption;
        $rootScope.$broadcast('updated');    
    }
}
<div ng-controller="controllera as vm">
    <ul>
        <li ng-repeat="item in vm.filtereditems">{{item.bar}}</li>
    </ul>
</div>