【问题标题】:How do I conditionally add a filter to ng-repeat inside directive?如何有条件地将过滤器添加到 ng-repeat inside 指令?
【发布时间】:2016-05-18 21:16:01
【问题描述】:

我在几个视图上使用元素指令。该指令对资源列表中的每个“资源”重复,就像这样:ng-repeat="resource in resources"

不同的页面控制器将通过在每个视图控制器中使用不同的 $scope.resourceApiPath 来确定将从 API 中提取哪些资源,然后指令控制器使用该 $http 调用。

这适用于显示不同资源的不同视图。比如一个视图显示所有用户自己的资源,一个视图显示公共资源,一个视图显示用户已加星标的资源等。

唯一的问题是,对于我的一个观点,我想在ng-repeat 上添加一个过滤器,如下所示:ng-repeat="resource in resources | filter:resourceSearch.text"。有没有办法让我根据条件添加这个过滤器,例如如果是$scope.filter == true;,否则只返回常规的ng-repeat="resource in resources"

这是我的指令:

.directive('resourcePanel', function() {
    return {
        restrict: 'E',
        scope: false,
        templateUrl: 'scripts/templates/resource-panel.html',
        controller: 'ResourcesPanelController'
    }
})

指令中引用的ResourcesPanelController 是这样的:

$scope.resources = [];
$scope.loadResources = function() {
    $scope.resources = []; // Empty the array
    $http.get('/api/resource' + $scope.resourceApiPath)
        .then(function(res) {
            $scope.resources = res.data.message;
        });
};
$scope.loadResources();

scripts/templates/resource-panel.html 元素模板如下所示:

<div class="panel" ng-repeat="resource in resources">
    {{resource.content}}
</div>

谢谢!

【问题讨论】:

    标签: javascript angularjs angularjs-directive angular-controller


    【解决方案1】:

    我认为你可以做四种方式之一,我更喜欢 1 和 3,但这完全取决于你的要求和代码标准,哪一种最适合你。

    自定义过滤器也是一个干净的解决方案。

    1. 如果您使用文本值进行过滤,那么如果您不设置 resourceSearch.text 的值,那么它与没有过滤器一样好,所以如果 resourceSearch.text 存在,它将过滤,如果它未定义,则没有过滤器。

      ng-repeat="资源中的资源 | filter:resourceSearch.text"

    2. 创建一个自定义过滤器并在那里处理它。

    如果您想创建自定义过滤器,请使用 enable 参数,您可以使用它来打开和关闭您的过滤器http://plnkr.co/edit/ilPJPUZkBC7Y5OvGHWey?p=preview 我找到了一个 plunkr 以及适合您需要的自定义过滤器

    ng-repeat="resource in resources | customfilter:resourceSearch.text:enable"
    
    1. 在控制器中过滤您的最终资源并将过滤后的值传递给 html

    2. 如果过滤器存在则使用 ng-if 和您的条件,则一个循环,如果不存在则另一个循环。

    我希望它会有所帮助。

    【讨论】:

    • 我决定使用您的 enable 参数,因为这是将它与我​​当前设置集成的最简单方法。谢谢!
    【解决方案2】:

    您可以使用自定义过滤功能:

    $scope.conditionalFilter = function(resource) {
        if (!$scope.filter) {
            return true;
        }
    
        // normal filter logic goes here, e.g.
        return resource.content.indexOf($scope.resourceSearch.text) >= 0;
    };
    

    然后在您的模板中使用自定义过滤器:

    <div class="panel" ng-repeat="resource in resources | filter:conditionalFilter">
        {{resource.content}}
    </div>
    

    【讨论】:

      【解决方案3】:
      <div ng-if="!filter" class="panel" ng-repeat="resource in resources">
          {{resource.content}}
      </div>
      <div ng-if="filter" class="panel" ng-repeat="resource in resources| filter:resourceSearch.text">
          {{resource.content}}
      </div>
      

      抱歉没有描述,如果我很确定它只出现一次,我有时会使用它,因为当你将它展平时......

      <div ng-if="!filter" class="panel" ng-repeat="resource in resources">{{resource.content}}</div>
      <div ng-if="filter" class="panel" ng-repeat="resource in resources|filter:resourceSearch.text">{{resource.content}}</div>
      

      那么它看起来真的没有那么糟糕。

      但更完整的解决方案是设置自定义过滤器并注入“过滤器”

      app.filter('conditionalFilter', function (filter) {
        return function (item, condition) {
          if(condition){
             return filter.bind(this,item).apply(this,[].slice.call(arguments,2));
          } else{ return item }
        };
      });
      

      然后

      <div class="panel" ng-repeat="resource in resources| conditionalfilter : !!filter : researchSearch.text" >
          {{resource.content}}
      </div>
      

      未测试,如有错误请告知。

      【讨论】:

      • 这个问题是我实际上已经大大简化了模板:实际上有大量的代码进入面板,所以这需要把它全部写两次,这很湿 -更不用说首先将其分离到模板中的原因。
      • @Aron WET 是 DRY 的对立面?这是一个新的:)
      • 请解释这是如何回答问题的。虽然 OP 可能知道您的意思,但并不是每个看到这个问题和答案的人都会知道,而且 Stack Overflow 是一个知识库,不是一个人可以得到帮助他们的帮助的地方
      • @shmosel,是的,它代表 Write Everything Twice :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-16
      • 2014-04-14
      • 1970-01-01
      • 1970-01-01
      • 2017-02-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多