Ng-Bind-Html inside ng-repeat

2019-09-08 12:02发布

问题:

I'm making a custom autosuggest component where I hit a web service with a search term and it returns a list of suggestions which I display.

My issue is, I want to bold the matching term inside the list and angular is not playing nice with the extra html. I've seen countless and countless examples using ng-bind-html which I've gotten to work if I can bind to specific values, but not with a dynamic list of values.

This is my first angular project so I'm sure there is something simple I'm missing. The code I'm posting renders the html correctly but it only displays the last result multiple times (I understand why).

How can I accomplish what I'm trying to do?


Here is my jade code :

#search-main(ng-controller="autocomplete" data-api-url="/autocomplete.json")
  input(type="search" placeholder="Search" ng-model="termToComplete")
  input(type="image" name="submit" src="/search-icon.gif", alt="Submit")
  ul.autoSuggest(ng-if="items.length")
    li.fade-in(ng-repeat="item in items")
      h2: a(href="{{item.url}}" ng-bind-html="html")

Here is some of my js

app.filter('html', ['$sce', function ($sce) { 
  return function (text) {
    return $sce.trustAsHtml(text);
  };    
}])

app.controller('autocomplete', function($scope, $element, $timeout, acAPIservice, $location, $sce){
  $scope.items = [];
  $scope.apiUrl = $element.attr('data-api-url');
  $scope.termToComplete = undefined;

  $scope.showSuggestion = function(){
  var payload = {
    term : $scope.termToComplete
  }

  acAPIservice.getSearch($scope.apiUrl, payload)
    .success(function(data){
      $scope.items = $scope.items.concat(data.results);
      $scope.findMatch();

   })
    .error(function(data, status, headers, config){      
      $scope.items = [];
   });
  }

  //iterates over the results and bolds matching terms
  $scope.findMatch = function(){
    var term = $scope.termToComplete;
    angular.forEach($scope.items, function(value, key){
    $scope.items[key].title = $sce.trustAsHtml($scope.items[key].title.replace(new RegExp('(^|)(' + term + ')(|$)','ig'), '$1<b>$2</b>$3'));
    $scope.html = $scope.items[key].title;
      });
   }


  $scope.$watch('termToComplete', function(newValue, oldValue) {
    // reset everything
    $scope.items = [];
    $scope.start = 0;
    $scope.end = 0;
    $scope.total = 0;
    // if we still have a search term go get it
    if($scope.termToComplete){
      $scope.showSuggestion();
    }
  });
});

Here is my test-Json :

{
    "start" : 1,
    "end" : 8,
    "total" : 27,
    "results" : [{
        "id" : 0,
        "title" : "here is a title",
        "url" : "google.com"
    }, {
        "id" : 1,
        "title" : "here is another title",
        "url" : "google.com"
    }, {
        "id" : 2,
        "title" : "and another title",
        "url" : "google.com"
    }]
}

NOTE:

acAPIservice is just a factory that hits an API and returns the data

回答1:

You don't need to define $scope.html because you are already assigning the HTML to title.

You just need to use it right in your ng-repeat loop:

li.fade-in(ng-repeat="item in items")
  h2: a(ng-href="{{item.url}}" ng-bind-html="item.title")

I also recommend using ng-href instead of just href, because you are using an angular expression for the link ;)