javascriptangularjsangularjs-ng-repeatng-bind

How do I highlight colors for search results?


Could you please help to highlight the words searched in yellow?

The below an example of code has been written to filter the words among the displayed data from JSON feed URL.

angular.module('sample', []).
controller('sampleController', ['$scope', '$http', function($scope, $http) {
  var url = "https://spreadsheets.google.com/feeds/list/153Obe1TdWlIPyveZoNxEw53rdrghHsiWU9l-WgGwCrE/od6/public/values?alt=json";

  $http.get(url)
    .success(function(data, status, headers, config) {
      $scope.users = data.feed.entry;
      console.log($scope.users);
    })
    .error(function(error, status, headers, config) {
      console.log(status);
      console.log("Error occured");
    });
   // code to highlight
   
    $scope.highlight = () => {
  //create copy of the original array
  $scope.filteredContent = JSON.parse(JSON.stringify($scope.users));

  $scope.filteredContent.forEach(fc => {
    const regEx = new RegExp($scope.search);
alert("here");
    fc.question = fc.gsx$topic.$t.replace(regEx, '<span class="highlight">${$scope.search}</span>');
    fc.answer = fc.gsx$response.$t.replace(regEx, '<span class="highlight">${$scope.search}</span>');
  });
};
    
  // code to highlight
   
$scope.search='';
$scope.searchFilter=function(item){

	if(item.gsx$topic.$t.toLowerCase().indexOf($scope.search.toLowerCase()) != -1 || item.gsx$response.$t.toLowerCase().indexOf($scope.search.toLowerCase()) != -1){
      return true;
    }
    return false;
  }

}]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.0/angular.min.js"></script>
<div ng-app="sample" ng-controller="sampleController">
  <div class="black">
    <input type="text" name="search" ng-keyup="highlight()" ng-model="search" placeholder="search"/>
  </div>
  <br>
  <br>
  <br>
  <table style="border: 1px solid black ;">
    <tbody>
      <tr>
        <td>
          <center><b>Question</b></center>
        </td>
        <td>
          <center><b>Response</b></center>
        </td>
      </tr>
      <tr ng-repeat="user in users | filter:searchFilter">
        <td style="border: 1px solid black ; width:30%;white-space: pre-wrap;" ng-bind-html="user.gsx$topic.$t">{{user.gsx$topic.$t}}</td>
        <td style="border: 1px solid black ; width:70%;white-space: pre-wrap;" ng-bind-html="user.gsx$response.$t">{{user.gsx$response.$t}}</td>
      </tr>
    </tbody>
  </table>
</div>

Code link: https://jsfiddle.net/bjqsgfzc/1/


Solution

  • You'll need to use the $sce service Strict Contextual Escaping.

    Add this service in your controller declaration, like this:

    controller('sampleController', ['$scope', '$http', '$sce', function($scope, $http, $sce) {
    

    Now you must define a function that will only inject a span tag with a CSS class name with the yellow color to highlight, when the searched text is found, through the $sce.trustAsHtml method, to indicate AngularJS, the injected is safe content.

    $scope.highlightText = function(text, search) {
      if (search && search.length === 0) {
    
        // Returns the default content.
        return $sce.trustAsHtml(text);
      }
    
      // Define a regular expression to find the text globally and ignoring capital letters.
      var regex = new RegExp(search, 'gi');
    
      // If you already found the text then inject a span element with CSS class to highlight that you found.
      return $sce.trustAsHtml(text.replace(regex, '<span class="foundText">$&</span>'));
    };
    

    In the previous regular expression replacement text, $& indicates to display the captured text that matches the regular expression within the replaced.

    In the HTML, within the ng-repeat, add the ngBindHtml directive with highlightText function where the first parameter is the text that you'll have to search and the second parameter is the text to find.

    In your case, in this way:

    <tr ng-repeat="user in users | filter:searchFilter">
            <td style="border: 1px solid black ; width:30%;white-space: pre-wrap;" ng-bind-html="highlightText(user.gsx$topic.$t, search)">{{user.gsx$topic.$t}}</td>
    

    See in this example:

    angular.module('sample', []).
    controller('sampleController', ['$scope', '$http', '$sce', function($scope, $http, $sce) {
      var url = "https://spreadsheets.google.com/feeds/list/153Obe1TdWlIPyveZoNxEw53rdrghHsiWU9l-WgGwCrE/od6/public/values?alt=json";
    
      $http.get(url)
        .success(function(data, status, headers, config) {
          $scope.users = data.feed.entry;
          console.log($scope.users);
        })
        .error(function(error, status, headers, config) {
          console.log(status);
          console.log("Error occured");
        });
      $scope.search = '';
      $scope.searchFilter = function(item) {
        if (item.gsx$topic.$t.indexOf($scope.search) != -1 || item.gsx$response.$t.indexOf($scope.search) != -1) {
          return true;
        }
        return false;
      };
    
      $scope.highlightText = function(text, search) {
        if (search && search.length === 0) {
    
          // Returns the default content.
          return $sce.trustAsHtml(text);
        }
    
        // Define a regular expression to find the text globally and ignoring capital letters.
        var regex = new RegExp(search, 'gi');
    
        // If you already found the text then inject a span element with CSS class to highlight that you found.
        return $sce.trustAsHtml(text.replace(regex, '<span class="foundText">$&</span>'));
      };
    }]);
    .foundText {
      background-color: #ff0;
      color: #f00;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.0/angular.min.js"></script>
    <div ng-app="sample" ng-controller="sampleController">
      <div class="black">
        <input type="text" name="search" ng-model="search" placeholder="search" ng-click="didSelectLanguage()" />
      </div>
      <br>
      <br>
      <br>
      <table style="border: 1px solid black ;">
        <tbody>
          <tr>
            <td>
              <center><b>Question</b></center>
            </td>
            <td>
              <center><b>Response</b></center>
            </td>
          </tr>
          <tr ng-repeat="user in users | filter:searchFilter">
            <td style="border: 1px solid black ; width:30%;white-space: pre-wrap;" ng-bind-html="highlightText(user.gsx$topic.$t, search)">{{user.gsx$topic.$t}}</td>
            <td style="border: 1px solid black ; width:70%;white-space: pre-wrap;" ng-bind-html="highlightText(user.gsx$response.$t, search)">{{user.gsx$response.$t}}</td>
          </tr>
        </tbody>
      </table>
    </div>

    Hope this helps!