web-dev-qa-db-fra.com

Mettre en évidence un résultat filtré dans AngularJS

J'utilise un ng-repeat et un filtre dans angularJS, comme le didacticiel sur les téléphones, mais j'aimerais mettre en évidence les résultats de la recherche dans la page. Avec jQuery de base, j'aurais simplement analysé la page sur les touches haut en entrée, mais j'essaie de le faire de manière angulaire. Des idées ?

Mon code:

<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>
54
Lukmo

En fait cela pour 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;
}
85
Dmitri Algazin

ui-utils angulaire ne prend en charge qu’un terme. J'utilise le filtre suivant plutôt qu'une fonction de portée:

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>'));
  };
});

Et le HTML:

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

Essayez Interface utilisateur angulaire

Filtres -> Highlite (filtre) . Il existe également une directive Keypress.

13
Dmitry

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)
    }
  })

Référence: http://codeforgeek.com/2014/12/highlight-search-result-angular-filter/ Demo: http://demo.codeforgeek.com/highlight-angular/

8
Shaikh Shahid

J'espère que mon exemple de lumière facilitera la compréhension:

  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>

 enter image description here

5
mrded

Il y a un filtre de surbrillance standart dans angular-bootstrap : typeaheadHighlight

Usage

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

Avec scope {text:"Hello world", query:"world"} rendu en 

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

En quittant la réponse de @ uri dans ce fil de discussion, je l'ai modifiée pour qu'elle fonctionne avec une chaîne unique OU un tableau de chaînes.

Voici le TypeScript version

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);
};

Ce qui se traduit en 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= {}));
;

Ou si vous voulez juste une implémentation JavaScript simple sans ces espaces de noms générés:

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;
        }
    };
}]);

&EACUTE;DIT&EACUTE;pour inclure un correctif qui aurait déjà été cassé c'est une personne recherchée pour . ou tout autre caractère ayant une signification dans une expression régulière. Maintenant, ces personnages sont d'abord échappés.

4
Chris Barr

Utilisez ng-class qui est appliqué lorsque le terme de recherche est lié aux données contenues dans l'élément.

Donc, sur vos éléments ng répétés, vous auriez ng-class="{ className: search_query==elementRelatedValue}"

qui appliquerait la classe "className" aux éléments de manière dynamique lorsque la condition est remplie.

1

Merci d’avoir posé cette question car c’était quelque chose que je traitais aussi.

Deux choses cependant:

Tout d’abord, la réponse est excellente, mais le commentaire est précis, ce qui dit que highlight () a un problème avec les caractères spéciaux. Ce commentaire suggère d'utiliser une chaîne d'échappement qui fonctionnera mais suggérera d'utiliser unescape () en cours de suppression. Ce que j'ai fini avec:

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

Deuxièmement, j'essayais de faire cela dans une liste d'URL liées aux données. Dans la chaîne de sélection (), vous n'avez pas besoin de lier les données.

Exemple:

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

Est devenu:

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

Je rencontrais des problèmes en les laissant entre {{}} et en obtenant toutes sortes d’erreurs.

J'espère que cela aide les personnes rencontrant les mêmes problèmes.

0
mattjay

En ce qui concerne les problèmes avec les caractères spéciaux, je pense qu’en vous évitant, vous risquez de perdre la recherche de regex. 

Et ça:

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>'));
};

Une expression rationnelle non valide pourrait être un utilisateur en tapant simplement le texte:

  • valide: m
  • invalide: m [
  • invalide: m [ô
  • invalide: m [ôo
  • valide: m [ôo]
  • valide: m [ôo] n
  • valide: m [ôo] ni
  • valide: m [ôo] nic
  • valide: m [ôo] nica

Que pensez-vous de @Mik Cox?

0
Andre Medeiros

Ma solution pour mettre en évidence, utilisé avec l'élément 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);
 });

Ajouter css:

.highlighted {
  color: orange;
}

HTML:

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

Et pour ajouter une entrée de recherche:

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

Une autre proposition:

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>' }}

Je suis ouvert à la critique! ;-)

0
Monkey Monk

Si vous utilisez la bibliothèque de matériaux angulaires, il existe une directive intégrée appelée md-highlight-text

De la documentation:

<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>

Lien vers docs: https://material.angularjs.org/latest/api/directive/mdHighlightText

0
Anthony