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

时间:2015-06-09 07:43:32

标签: javascript angularjs

我有两个控制器和一个共享服务。控制器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以某种方式通知controllera控制器b中的选项已更改并且需要更新(例如通过手动注入自定义过滤器并运行它)?

总而言之,我对如何使这项工作感到困惑,并采取最佳方法。

2 个答案:

答案 0 :(得分:1)

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

你可以开始搞乱$scope.$digest()$timeout(func, 0),但它们非常难看,远非“最佳实践”。我宁愿建议使用$timeout(),因为这也会导致对范围进行脏检查。所以这个过程:

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

答案 1 :(得分:0)

我已设法使用$rootScope.$broadcast$scope.$on实现此目的。

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

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>