【问题标题】:Highlighting a filtered result in AngularJS在 AngularJS 中突出显示过滤后的结果
【发布时间】:2013-03-09 07:42:24
【问题描述】:

我在 angularJS 中使用 ng-repeat 和过滤器,就像电话教程一样,但我想突出显示页面中的搜索结果。使用基本的 jQuery,我会简单地在输入键上解析页面,但我正在尝试以有角度的方式来做。有什么想法吗?

我的代码:

<input id="search" type="text" placeholder="Recherche DCI" ng-model="search_query" autofocus>
<tr ng-repeat="dci in dcis | filter:search_query">
            <td class='marque'>{{dci.marque}} ®</td>
            <td class="dci">{{dci.dci}}</td>
 </tr>

【问题讨论】:

  • 你可以注册一个keyup监听器为given here

标签: angularjs angularjs-ng-repeat


【解决方案1】:

我的高亮解决方案,将其与 angular-ui-tree 元素一起使用:https://codepen.io/shnigi/pen/jKeaYG

angular.module('myApp').filter('highlightFilter', $sce =>
 function (element, searchInput) {
   element = element.replace(new RegExp(`(${searchInput})`, 'gi'),
             '<span class="highlighted">$&</span>');
   return $sce.trustAsHtml(element);
 });

添加css:

.highlighted {
  color: orange;
}

HTML:

<p ng-repeat="person in persons | filter:search.value">
  <span ng-bind-html="person | highlightFilter:search.value"></span>
</p>

并添加搜索输入:

<input type="search" ng-model="search.value">

【讨论】:

    【解决方案2】:

    如果您使用的是角度材质库,则有一个名为 md-highlight-text 的内置指令

    来自文档:

    <input placeholder="Enter a search term..." ng-model="searchTerm" type="text">
    <ul>
      <li ng-repeat="result in results" md-highlight-text="searchTerm">
        {{result.text}}
      </li>
    </ul>
    

    文档链接:https://material.angularjs.org/latest/api/directive/mdHighlightText

    【讨论】:

      【解决方案3】:

      我希望我的简单示例能让您更容易理解:

        app.filter('highlight', function() {
          return function(text, phrase) {
            return phrase 
              ? text.replace(new RegExp('('+phrase+')', 'gi'), '<kbd>$1</kbd>') 
              : text;
          };
        });
      

        <input type="text" ng-model="search.$">
      
        <ul>
          <li ng-repeat="item in items | filter:search">
            <div ng-bind-html="item | highlight:search.$"></div>
          </li>
        </ul>
      

      【讨论】:

      • 这里的phrasetext 是什么?
      • 这看起来不错,我正在努力解决。第一次尝试以“angular.js:14516 Error: [$injector:unpr]”结尾。所以我想弄清楚我是否必须在某处注入过滤器。现在没有运气。有什么线索吗?
      • 好的,为我在过滤器中返回一个函数工作。并且不使用 $.我还必须用 $sce 保护 html。
      • 伙计们,请不要在我的示例中添加$sce。这只是一个例子,它必须简单易懂。如果您需要 - 将其包装在您的代码中。谢谢。
      【解决方案4】:

      从@uri 在此线程中的回答出发,我将其修改为使用单个字符串 OR 字符串数组。

      这是 TypeScript 版本

      module myApp.Filters.Highlight {
          "use strict";
      
          class HighlightFilter {
              //This will wrap matching search terms with an element to visually highlight strings
              //Usage: {{fullString | highlight:'partial string'}}
              //Usage: {{fullString | highlight:['partial', 'string, 'example']}}
      
              static $inject = ["$sce"];
      
              constructor($sce: angular.ISCEService) {
      
                  // The `terms` could be a string, or an array of strings, so we have to use the `any` type here
                  /* tslint:disable: no-any */
                  return (str: string, terms: any) => {
                      /* tslint:enable */
      
                      if (terms) {
                          let allTermsRegexStr: string;
      
                          if (typeof terms === "string") {
                              allTermsRegexStr = terms;
                          } else { //assume a string array
                              // Sort array by length then  join with regex pipe separator
                              allTermsRegexStr = terms.sort((a: string, b: string) => b.length - a.length).join('|');
                          }
      
                      //Escape characters that have meaning in regular expressions
                      //via: http://stackoverflow.com/a/6969486/79677
                      allTermsRegexStr = allTermsRegexStr.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
      
                          // Regex to simultaneously replace terms - case insensitive!
                          var regex = new RegExp('(' + allTermsRegexStr + ')', 'ig');
      
                          return $sce.trustAsHtml(str.replace(regex, '<mark class="highlight">$&</mark>'));
                      } else {
                          return str;
                      }
                  };
              }
          }
      
          angular
              .module("myApp")
              .filter("highlight", HighlightFilter);
      };
      

      这在 JavaScript 中转化为:

      var myApp;
      (function (myApp) {
          var Filters;
          (function (Filters) {
              var Highlight;
              (function (Highlight) {
                  "use strict";
                  var HighlightFilter = (function () {
                      function HighlightFilter($sce) {
                          // The `terms` could be a string, or an array of strings, so we have to use the `any` type here
                          /* tslint:disable: no-any */
                          return function (str, terms) {
                              /* tslint:enable */
                              if (terms) {
                                  var allTermsRegexStr;
                                  if (typeof terms === "string") {
                                      allTermsRegexStr = terms;
                                  }
                                  else {
                                      // Sort array by length then  join with regex pipe separator
                                      allTermsRegexStr = terms.sort(function (a, b) { return b.length - a.length; }).join('|');
                                  }
      
                                  //Escape characters that have meaning in regular expressions
                                  //via: http://stackoverflow.com/a/6969486/79677
                                  allTermsRegexStr = allTermsRegexStr.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
      
                                  // Regex to simultaneously replace terms - case insensitive!
                                  var regex = new RegExp('(' + allTermsRegexStr + ')', 'ig');
                                  return $sce.trustAsHtml(str.replace(regex, '<mark class="highlight">$&</mark>'));
                              }
                              else {
                                  return str;
                              }
                          };
                      }
                      //This will wrap matching search terms with an element to visually highlight strings
                      //Usage: {{fullString | highlight:'partial string'}}
                      //Usage: {{fullString | highlight:['partial', 'string, 'example']}}
                      HighlightFilter.$inject = ["$sce"];
                      return HighlightFilter;
                  })();
                  angular.module("myApp").filter("highlight", HighlightFilter);
              })(Highlight = Filters.Highlight || (Filters.Highlight = {}));
          })(Filters = myApp.Filters || (myApp.Filters = {}));
      })(myApp|| (myApp= {}));
      ;
      

      或者,如果您只是想要一个简单的 JavaScript 实现,而不需要那些生成的命名空间:

      app.filter('highlight', ['$sce', function($sce) {
          return function (str, terms) {
              if (terms) {
                  var allTermsRegexStr;
                  if (typeof terms === "string") {
                      allTermsRegexStr = terms;
                  }
                  else {
                      // Sort array by length then  join with regex pipe separator
                      allTermsRegexStr = terms.sort(function (a, b) { return b.length - a.length; }).join('|');
                  }
      
                  //Escape characters that have meaning in regular expressions
                  //via: http://stackoverflow.com/a/6969486/79677
                  allTermsRegexStr = allTermsRegexStr.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
      
                  // Regex to simultaneously replace terms - case insensitive!
                  var regex = new RegExp('(' + allTermsRegexStr + ')', 'ig');
                  return $sce.trustAsHtml(str.replace(regex, '<mark class="highlight">$&</mark>'));
              }
              else {
                  return str;
              }
          };
      }]);
      

      EDITED 包含以前会破坏的修复程序,这是某人搜索了. 或任何其他在正则表达式中有意义的字符。现在这些字符首先被转义。

      【讨论】:

      • 转义| 将阻止正则表达式。应该是这样的var escape = new RegExp('[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\^\\$\\|]', 'g'); var termsEscaped : string [] = new Array(); terms.sort((a: string, b: string) =&gt; b.length - a.length).forEach( (value:string, index: number, array : string[]) : void =&gt; { termsEscaped.push(value.replace(escape, "\\$&amp;")); }); var allTermsRegexStr : string = termsEscaped.join('|');
      【解决方案5】:

      angular-bootstrap:typeaheadHighlight中有标准的高光滤镜

      用法

      <span ng-bind-html="text | typeaheadHighlight:query"></span>
      

      {text:"Hello world", query:"world"} 范围内渲染

      <span...>Hello <strong>world</strong></span>
      

      【讨论】:

        【解决方案6】:

        angular ui-utils 只支持一个术语。我使用的是以下过滤器而不是作用域函数:

        app.filter('highlight', function($sce) {
          return function(str, termsToHighlight) {
            // Sort terms by length
            termsToHighlight.sort(function(a, b) {
              return b.length - a.length;
            });
            // Regex to simultaneously replace terms
            var regex = new RegExp('(' + termsToHighlight.join('|') + ')', 'g');
            return $sce.trustAsHtml(str.replace(regex, '<span class="match">$&</span>'));
          };
        });
        

        还有 HTML:

        <span ng-bind-html="theText | highlight:theTerms"></span>
        

        【讨论】:

        • 我得到一个错误,`TypeError: undefined is not a function` when using this...
        • theTerms 应该是一个字符串数组。
        • 我必须先这样做:termsToHighlight = termsToHighlight.split(" ");,然后再进行排序。
        • 另外它也不适用于大小写,所以 'lorem' 不匹配 'Lorem'
        • 所以我做了var regex = new RegExp('(' + termsToHighlight.join('|') + ')', 'ig');
        【解决方案7】:

        index.html

        <!DOCTYPE html>
        <html>
          <head>
            <script src="angular.js"></script>
            <script src="app.js"></script>
            <style>
              .highlighted { background: yellow }
            </style>
          </head>
        
          <body ng-app="Demo">
            <h1>Highlight text using AngularJS.</h1>
        
            <div class="container" ng-controller="Demo">
              <input type="text" placeholder="Search" ng-model="search.text">
        
              <ul>
                <!-- filter code -->
                <div ng-repeat="item in data | filter:search.text"
                   ng-bind-html="item.text | highlight:search.text">
                </div>
              </ul>
            </div>
          </body>
        </html>
        

        app.js

        angular.module('Demo', [])
          .controller('Demo', function($scope) {
            $scope.data = [
              { text: "<< ==== Put text to Search ===== >>" }
            ]
          })
          .filter('highlight', function($sce) {
            return function(text, phrase) {
              if (phrase) text = text.replace(new RegExp('('+phrase+')', 'gi'),
                '<span class="highlighted">$1</span>')
        
              return $sce.trustAsHtml(text)
            }
          })
        

        参考:http://codeforgeek.com/2014/12/highlight-search-result-angular-filter/ 演示:http://demo.codeforgeek.com/highlight-angular/

        【讨论】:

        • 如果你想 ng-bind-html 不仅仅是 item.text 而是所有 item 怎么办?
        • 如何在表格中实现相同的功能?
        • 效果很好,但对我不起作用,因为我使用的是树元素,这会跳过整个元素,只返回 span
        【解决方案8】:

        感谢您提出这个问题,因为这也是我正在处理的问题。

        不过有两件事:

        首先,最佳答案很棒,但是关于 highlight() 的特殊字符有问题的评论是准确的。该评论建议使用可以工作的转义链,但他们建议使用正在逐步淘汰的 unescape() 。我最终得到了什么:

        $sce.trustAsHtml(decodeURI(escape(text).replace(new RegExp(escape(search), 'gi'), '<span class="highlightedText">$&</span>')));
        

        其次,我试图在 URL 的数据绑定列表中执行此操作。在 highlight() 字符串中,您不需要数据绑定。

        例子:

        <li>{{item.headers.host}}{{item.url}}</li>
        

        成为:

        <span ng-bind-html="highlight(item.headers.host+item.url, item.match)"></span>
        

        将它们留在 {{ }} 中时遇到问题并出现各种错误。

        希望这对遇到同样问题的人有所帮助。

        【讨论】:

        • 我在让它工作时遇到了各种各样的麻烦。 “, item.match”在你的代码中对应什么?
        • 对不起,@richfinelli,这让我很困惑。这是 ng 重复表的一部分。
          好的,在我的情况下,我可以不考虑它。我可能需要的只是...... ng-bind-html="highlight(item.something)"
        【解决方案9】:

        另一个命题:

        app.filter('wrapText', wrapText);
        
        function wrapText($sce) {
            return function (source, needle, wrap) {
                var regex;
        
                if (typeof needle === 'string') {
                    regex = new RegExp(needle, "gi");
                } else {
                    regex = needle;
                }
        
                if (source.match(regex)) {
                    source = source.replace(regex, function (match) {
                        return $('<i></i>').append($(wrap).text(match)).html();
                    });
                }
        
                return $sce.trustAsHtml(source);
            };
        } // wrapText
        
        wrapText.$inject = ['$sce'];
        
        // use like this
        $filter('wrapText')('This is a word, really!', 'word', '<span class="highlight"></span>');
        // or like this
        {{ 'This is a word, really!' | wrapText:'word':'<span class="highlight"></span>' }}
        

        我愿意接受批评! ;-)

        【讨论】:

          【解决方案10】:

          关于特殊字符的问题,我认为只是逃避你可能会失去正则表达式搜索。

          这个呢:

          function(text, search) {
              if (!search || (search && search.length < 3)) {
                  return $sce.trustAsHtml(text);
              }
          
              regexp  = '';
          
              try {
                  regexp = new RegExp(search, 'gi');
              } catch(e) {
                  return $sce.trustAsHtml(text);
              }
          
              return $sce.trustAsHtml(text.replace(regexp, '<span class="highlight">$&</span>'));
          };
          

          一个无效的正则表达式可能是用户只输入文本:

          • 有效:m
          • 无效:m[
          • 无效:m[ô
          • 无效:m[ôo
          • 有效:m[ôo]
          • 有效:m[ôo]n
          • 有效:m[ôo]ni
          • 有效:m[ôo]nic
          • 有效:m[ôo]nica

          @Mik Cox 你怎么看?

          【讨论】:

            【解决方案11】:

            在 AngularJS v1.2+ 中这样做了

            HTML:

            <span ng-bind-html="highlight(textToSearchThrough, searchText)"></span>
            

            JS:

            $scope.highlight = function(text, search) {
                if (!search) {
                    return $sce.trustAsHtml(text);
                }
                return $sce.trustAsHtml(text.replace(new RegExp(search, 'gi'), '<span class="highlightedText">$&</span>'));
            };
            

            CSS:

            .highlightedText {
                background: yellow;
            }
            

            【讨论】:

            • 需要注意的是上面有特​​殊字符的问题,比如匹配(或者&等返回 $sce.trustAsHtml 的 unescape() 版本,它似乎可以正确处理特殊字符:return $sce.trustAsHtml(unescape(escape(text).replace(new RegExp(escape(search), 'gi'), '&lt;span class="highlightedText"&gt;$&amp;&lt;/span&gt;')));
            • 如果搜索文本出现在某个链接中怎么办?比如搜索apple,返回的html包含http://www.apple.com。它不会破坏链接吗?
            • 你应该使用这个函数RegExp.quote = function(str) { return (str+'').replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&amp;"); };转义特殊字符像这样:new RegExp(RegExp.quote(search), 'gi')
            • 详细说明 Mik Cox 的评论;由于不推荐使用“escape”和“unes​​cape”,因此可以分别用“encodeURI”和“decodeURI”替换它们,以进行简单的转义。
            • 你能解释一下gi$&amp; 是什么意思吗...拜托
            【解决方案12】:

            试试Angular UI

            过滤器-> Highlite(过滤器)。 还有 Keypress 指令。

            【讨论】:

            • AFAIK 这仅适用于一个学期。如果您同时需要多个解决方案,则需要不同的解决方案。
            • 你能链接到页面吗?我找不到它
            • 高亮过滤器不再可用,它已被弃用。转到github.com/angular-ui/ui-utils 以使用已弃用的代码。
            【解决方案13】:

            使用当搜索词与元素包含的数据相关时应用的 ng-class。

            所以在你的 ng-repeated 元素上,你会有ng-class="{ className: search_query==elementRelatedValue}"

            当条件满足时,将类“className”动态应用于元素。

            【讨论】:

            • 我必须很快发货,所以我最终会使用 angularUI 过滤器,但我会在本周末尝试理解你的答案,因为它会让我更好地理解角度方式。谢谢!
            猜你喜欢
            • 1970-01-01
            • 2018-03-25
            • 2017-11-05
            • 2012-01-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-01-29
            相关资源
            最近更新 更多