3

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/

  • possible duplicate of https://stackoverflow.com/questions/15519713/highlighting-a-filtered-result-in-angularjs – Risalat Zaman Feb 04 '20 at 06:56
  • Does this answer your question? [Highlighting a filtered result in AngularJS](https://stackoverflow.com/questions/15519713/highlighting-a-filtered-result-in-angularjs) – Danny Fardy Jhonston Bermúdez Feb 04 '20 at 07:22
  • Hey @DannyFardyJhonstonBermúdez/ @Risalat I tried this suggestion since I'm getting data from JSON URL like gsx$topic.$t and filtering results. I'm not getting how to implement the highlight. Can you help in implementing in my code? – Tejo Sai Kumar EEPU Feb 05 '20 at 05:19
  • @TejoSaiKumarEEPU Hi, see my answer. – Danny Fardy Jhonston Bermúdez Feb 05 '20 at 05:26
  • since I'm getting Cross-Origin Read Blocking (CORB) error so used the http.jsonp() instead of http.get(). But now the replace is not working it is showing below error. can you help. TypeError: Cannot read property 'replace' of undefined at a.$$childScopeClass.$$childScopeClass.$scope.highlightText – Tejo Sai Kumar EEPU Feb 05 '20 at 11:08

2 Answers2

1

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!

  • you are really awesome! this is working. I have one more query I'm able to access topic and response from JSON URL but I also want to get the title name and hyperlinks to be displayed and upon filter, the title should not go off. Can you please – Tejo Sai Kumar EEPU Feb 05 '20 at 05:45
  • Hey @Danny since I'm getting Cross-Origin Read Blocking (CORB) error so used the http.jsonp() instead of http.get(). But now the replace is not working it is showing below error. can you help. TypeError: Cannot read property 'replace' of undefined at a.$$childScopeClass.$$childScopeClass.$scope.highlightText – Tejo Sai Kumar EEPU Feb 05 '20 at 10:32
  • Hi @TejoSaiKumarEEPU. About your first question. Can you be more specific? – Danny Fardy Jhonston Bermúdez Feb 05 '20 at 17:27
  • About the CORB I think it was the result of a temporary restriction. Reviewing the URL response in detail https://spreadsheets.google.com/feeds/list/153Obe1TdWlIPyveZoNxEw53rdrghHsiWU9l-WgGwCrE/od6/public/values?alt=json the `content-type: application/json; charset=UTF-8`, so there is no reason to use **`$http.jsonp`**. See in this link: https://pasteboard.co/ITiSwZW.png. – Danny Fardy Jhonston Bermúdez Feb 05 '20 at 17:34
  • The response header has `access-control-allow-origin: *`, so you can request by using **`XMLHttpRequest`** like **`$http.get`** for AngularJS from remote domain. – Danny Fardy Jhonston Bermúdez Feb 05 '20 at 17:37
  • you are right I'm able to access the data and display from the URL mentioned in code. Sorry, I forgot to tell you my requirement is to get from the url as https://spreadsheets.google.com/feeds/list/1OJX_UfZ7KQ-NMKcpXmYT8Ml1OfzerPnmUyEcSoMqeZc/1/public/values?alt=json. This is giving CORS error. I'm getting status code as Status Code: 302. can you please try with the new URL. – Tejo Sai Kumar EEPU Feb 06 '20 at 06:28
  • So I have used var proxy = "//cors-anywhere.herokuapp.com"; $http.get(proxy+'/'+url1) instead of $http.get(url). So it is getting code: 202 in headers and with file size. But data is not getting displayed. but i saw in headers the file has loaded little late when compared to the other url previously which I mentioned in code. Can you please help to get this data displayed – Tejo Sai Kumar EEPU Feb 06 '20 at 11:47
0

You can add <span> with highlighted class. Make sure to create a deep copy of the original array. I used JSON.parse(JSON.stringify(...)). In addition, since we are adding the <span> and want to display it as html, we need to use ng-bind-html. In order to do that, we need to add ngSanitize as module dependency.

angular.module('myApp', ['ngSanitize'])
  .controller('myController', ['$scope', ($scope) => {
    const content = [{
        question: 'Question 1',
        answer: 'Answer 1'
      },
      {
        question: 'Question 2',
        answer: 'Answer 2'
      }
    ];

    //create copy of the original array
    $scope.filteredContent = JSON.parse(JSON.stringify(content));

    $scope.highlight = () => {
      //create copy of the original array
      $scope.filteredContent = JSON.parse(JSON.stringify(content));

      $scope.filteredContent.forEach(fc => {
        const regEx = new RegExp($scope.searchText);

        fc.question = fc.question.replace(regEx, `<span class="highlight">${$scope.searchText}</span>`);
        fc.answer = fc.answer.replace(regEx, `<span class="highlight">${$scope.searchText}</span>`);
      });
    };
  }]);
table {
  border-collapse: collapse;
  margin-top: 10px;
  border: 1pt solid black;
  width: 100%;
}

td {
  border: 1pt solid black;
  margin: 0;
  padding: 0;
}

.highlight {
  background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-sanitize/1.7.9/angular-sanitize.js"></script>

<div ng-app="myApp" ng-controller="myController">
  <input type="text" ng-model="searchText" ng-keyup="highlight()" placeholder="Search">

  <table>
    <tr ng-repeat="c in filteredContent">
      <td ng-bind-html="c.question">
      </td>
      <td ng-bind-html="c.answer">
      </td>
    </tr>
  </table>
</div>
Aditya Bhave
  • 998
  • 1
  • 5
  • 10
  • Hi @Aditya Bhave thanks for your help. I tried to use ngSanitize but the actual results are coming blank and I have updated my code with highlighting color code as per your suggestion. Can you please help to make work as per my code. – Tejo Sai Kumar EEPU Feb 05 '20 at 05:21
  • Did you add `angular-sanitize.js` javascript file in your application bundle ? or in your `index.html` ? – Aditya Bhave Feb 05 '20 at 09:07
  • No Aditya, I didn't – Tejo Sai Kumar EEPU Feb 05 '20 at 10:13
  • since I'm getting Cross-Origin Read Blocking (CORB) error so used the http.jsonp() instead of http.get(). But now the replace is not working it is showing below error. can you help. TypeError: Cannot read property 'replace' of undefined at a.$$childScopeClass.$$childScopeClass.$scope.highlightText @Aditya Bhave – Tejo Sai Kumar EEPU Feb 05 '20 at 11:07
  • Your object is `null` or `undefined`. Try logging the value and debug it. – Aditya Bhave Feb 05 '20 at 12:37