【问题标题】:Filtering some data with two kind of filter in AngularJs but not working在AngularJs中使用两种过滤器过滤一些数据但不起作用
【发布时间】:2016-01-06 05:40:20
【问题描述】:

嗯,我有这个plunkr 试图模拟我的情况:

这个想法是用户在文本框中键入一个单词,当单击按钮时,角度服务会根据在文本框中键入的内容从数据库返回答案(结果)(我已经用请求数据模拟了这个过程到一个 json 文件,所以无论你输入什么都不重要,总是会返回整个数据)并填充一个表。

但现在,我正在使用过滤器搜索。在此文本框中,您可以搜索由以下人员定义的人员:

  • 名字
  • 中间名
  • 姓氏
  • second_surname

我已经实现了两种视觉过滤器:

1) 用于隐藏和显示结果的可视化过滤器:(在 appCtrl.js 中定义)

$scope.changedValue=function(){
    var condition = $scope.filter.condition;
    $scope.Model.filteredlist = filterFilter($scope.Model.expenses,function(value, index, array){
      var fullname = (value.first_name+' '+value.middle_name+' '+value.first_surname+' '+value.second_surname).toLowerCase();
      if (fullname.indexOf(condition.replace(/\s\s+/g, ' ').toLowerCase()) > -1 ) {
        return array;
      }
    });
    if (typeof $scope.Model.filteredlist != 'undefined') { // When page loads for first time
      $scope.setPage();
    }
  } 

2) 用于突出显示结果的视觉过滤器:(在 appDrct.js 中定义)

app.directive('highLight', function ($document, $sce) {
  var component = function(scope, element, attrs) {

    if (!attrs.highlightClass) {
      attrs.highlightClass = 'angular-highlight';
    }

    var replacer = function(match, item) {
      return '<span class="'+attrs.highlightClass+'">'+match+'</span>';
    }

    var tokenize = function(keywords) {
      keywords = keywords.replace(new RegExp(',$','g'), '').split(' ');
      var i;
      var l = keywords.length;
      for (i=0;i<l;i++) {
        keywords[i] = keywords[i].replace(new RegExp('^ | $','g'), '');
      }
      return keywords;
    }

    scope.$watch('keywords', function(newValue, oldValue) {
      console.log("new: " + newValue + " old " + oldValue);

        var tokenized = tokenize(newValue);
        var regex     = new RegExp(tokenized.join('|'), 'gmi');

        if(newValue.length>=1 || oldValue.length>=1){
          for(i=0;i<=1;i++){
            element[0].cells[i].innerHTML = element[0].cells[i].innerText.replace(regex, replacer);
          }
        }
    });
  }
  return {
    link:       component,
    replace:    false,
    scope:      {
      keywords:  '=highLight'
    }
  };
});

调用这些过滤器的 html:(在 table.html 中定义)

<input type="text" class="form-control" id="filter-list" placeholder="Name(s) and/or Lastname(s)" ng-model="filter.condition" ng-change="changedValue()">
......
<tr ng-repeat="expense in Model.filteredlist | pagination: pagination.currentPage : numPerPage" x-high:light="filter.condition">
        <td>{{expense.first_name}} {{expense.middle_name}}</td>
        <td>{{expense.first_surname}} {{expense.second_surname}}</td>
        <td>{{expense.age}}</td>
      </tr>

但我遇到了一些问题,因为有时这个人没有 middle_name 或者有时没有 second_surname。

要重现我的问题,请在搜索框中输入:Lora,然后将其删除,您会看到某些数据未以正确的方式呈现。如果您键入 Loras 并擦除 s,则该单词不会再次突出显示,但如果您继续擦除,该单词会再次突出显示。

那么,我做错了什么?我认为这是$scope.changeValue 过滤器的问题,但我迷路了。

有什么想法吗?

【问题讨论】:

    标签: javascript angularjs angularjs-directive filtering angularjs-filter


    【解决方案1】:

    我相信您遇到的问题出在您的 highLight 指令中。 它正在尝试修改其内容并对其内容进行假设...

    element[0].cells[i].innerHTML = element[0].cells[i].innerText.replace(regex, replacer);

    事实上,问题是时间问题之一。 highLight 指令有时会在插值发生之前修改 HTML。所以你最终会得到类似的东西:

    <td class="ng-binding">{{expense.first_name}} {{expense.midd<span class="angular-highlight">l</span>e_name}}</td>

    这显然是 Angular 无法理解的。

    【讨论】:

    • 感谢您的回答,这是让我找到解决方案的主要线索。
    【解决方案2】:

    似乎是 Angular 的一个未解决问题 - https://github.com/angular/angular.js/issues/11716

    如果您将 {{ }} 绑定更改为 ng-bind,过滤将按您的预期工作 -

        <td><span ng-bind="expense.first_name"></span><span ng-bind="expense.middle_name"></span></td>
        <td><span ng-bind="expense.first_surname"></span><span ng-bind="expense.second_surname"></span></td>
        <td><span ng-bind="expense.age"></span></td>
    

    ----- UPDATE - Jan,4, 2016 -----

    我还没有找到令人满意的解释。该行为似乎与ng-bind 用于$watch 事物和{{ }} 用于$observe 的方式有关,我不太确定。

    根据角度最佳实践 - https://github.com/angular/angular.js/blob/2a156c2d7ec825ff184480de9aac4b0d7fbd5275/src/ng/directive/ngBind.js#L16ng-bind 是绑定 scope 中的值的首选方式,除非这些是 DOM 属性,在这种情况下,您可以 $observer 指令中的属性。参考——AngularJS : Difference between the $observe and $watch methods

    还有一个区别——{{ }} 观察器在每个 $digest 上触发,而 ng-bind$watch 用于更改,因此 ng-bind 的性能更好,即使您最终编写更多的html。参考——AngularJS : Why ng-bind is better than {{}} in angular?

    ----- UPDATE - Jan,5, 2016 -----

    Pete BD 的正确答案见下文

    【讨论】:

    • 哇,太棒了!但是为什么会这样呢?为什么当我使用{{}} 时,角度的行为不能按预期工作?
    • @robe007 我必须深入研究 Angular 代码才能解决这个问题 :) 但似乎很有趣。根据我目前的理解,它们应该以相同的方式工作,但看起来还有其他事情发生。
    • @robe007 我会在找到解释后立即编辑我的答案。感谢您接受我的回答。
    • @robe007 查看我对答案的更新。它仍然不够令人信服,但它的方向是正确的。
    • 非常感谢您的努力,我从您的回答中学到了很多。现在,我将自己的答案标记为已接受,因为这正是我所需要的。
    【解决方案3】:

    好吧,根据 FrailWordsPeteBD 的出色回答,我有了一个想法,现在可以工作了!

    诀窍在于插值。查看the docs 并找到了一个出色的fiddle,解决方案是使用$interpolate$evalnon isolated scope

    var interpolation = $interpolate(element[0].cells[i].innerText);
    element[0].cells[i].innerHTML = scope.$eval(interpolation).replace(regex, replacer);
    

    整个指令的代码:

    app.directive('highLight', ['$interpolate', function ($interpolate) {
      var component = function(scope, element, attrs) {
    
        if (!attrs.highlightClass) {
          attrs.highlightClass = 'angular-highlight';
        }
    
        var replacer = function(match, item) {
          return '<span class="'+attrs.highlightClass+'">'+match+'</span>';
        }
    
        var tokenize = function(keywords) {
          keywords = keywords.replace(new RegExp(',$','g'), '').split(' ');
          var i;
          var l = keywords.length;
          for (i=0;i<l;i++) {
            keywords[i] = keywords[i].replace(new RegExp('^ | $','g'), '');
          }
          return keywords;
        }
    
        scope.$watch(attrs.highLight, function(newValue, oldValue) {
          console.log("new: " + newValue + " old " + oldValue);
    
            var tokenized = tokenize(newValue);
            var regex     = new RegExp(tokenized.join('|'), 'gmi');
    
            if(newValue.length>=1 || oldValue.length>=1){
              for(i=0;i<=1;i++){
                var interpolation = $interpolate(element[0].cells[i].innerText);
                element[0].cells[i].innerHTML = scope.$eval(interpolation).replace(regex, replacer);
              }
            }
        });
      }
      return {
        link:       component,
        replace:    false
      };
    }]);
    

    而且 html 总是这样:

    <tr ng-repeat="expense in Model.filteredlist | pagination: pagination.currentPage : numPerPage" x-high:light="filter.condition">
     <td>{{expense.first_name}} {{expense.middle_name}}</td>
     <td>{{expense.first_surname}} {{expense.second_surname}}</td>
     <td>{{expense.age}}</td>
    </tr>
    

    现在一切都像魅力一样运作。很棒,但真的

    【讨论】:

      猜你喜欢
      • 2015-09-17
      • 2015-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多