Saad
Saad

Reputation: 28496

dynamically add span around angularjs data

Currently I'm reading data from an input field that gets pushed into an object in the controller, the data is then displayed in the view as following:

<ul class="status_list">
  <li data-ng-repeat="comment in comments" class="status">
    {{ comment.data }}
  </li>
</ul

I want to make it so if comment.data contains #word, it's replaced with <span class='x'>#word</span>. But I'm not quite sure how to: 1) search through the data in the view 2) append html to it

Upvotes: 2

Views: 3319

Answers (4)

Ed_
Ed_

Reputation: 19098

For anyone stumbling upon this question more recently, here is an updated version of @mikel's answer (ng-bind-html-unsafe has been deprecated since angular v 1.2.0). Instead, you have to mark the html as trusted and use ng-bind-html.

The following custom filter will add a span to all hashtags (coffeescript):

angular.module('myApp', ['ngSanitize'])
.filter('pxnHashtagHighlight', ($sce)->
  (value)->
    hashtags = /(?:^|\s)(#(\w+))/gm
    $sce.trustAsHtml(value.replace(hashtags, ' <span class="tag">$1</span>'))
)

Which can be used with the following markup (jade):

div.example(ng-bind-html="comment.data | pxnHashtagHighlight")

Notes

  • Because we want to add html we can't use plain ng-bind or the {{ }} shorthand.
  • This method is dependent on $sce to mark the html as trusted. In newer android versions this has been removed from core into the ngSanitise module, so you'll have to download that and add it as a dependency for your app.

Upvotes: 0

m.e.conroy
m.e.conroy

Reputation: 3538

I'd use a filter. {{ comment.data | mkSpan }}

angular.module('myapp.filters', [])
    .filter('mkSpan', function () {
        return function (input,klass) {
            if(angular.isDefined(input)){
                return (angular.isDefined(klass)) ? '<span class="' + klass + '">' + input + '</span>' : '<span>' + input + '</span>';
            }
            return input;
        }
}); // end mkSpan / myapp.filters

angular.module('myapp',['myapp.filters']);

{{ comment.data | mkSpan:myCssClass }}

Upvotes: 0

Michael Low
Michael Low

Reputation: 24506

You can do this using a custom filter.

app.filter("AddSpan", function() {
  return function(item) {

    if (item.indexOf("#word") > -1) {
      return "<span class='x'>" + item + "</span>";
    } else {
      return item;
    }
  }
});

Because you're adding HTML dynamically you also need to tell Angular to bind it 'unsafely' rather than escaping the HTML as it will do by default.

  <li data-ng-repeat="comment in comments" class="status" ng-bind-html-unsafe="comment.data | AddSpan"></li>

IMO this is a cleaner solution than adding a method to $scope - I don't think HTML belongs in the controller, and filters are designed for cases just like this when you just want to modify the appearance of the data.

Upvotes: 2

Keith
Keith

Reputation: 21244

Consider dynamically adding the spans via Javascript, then using ng-bind-html-unsafe to bind that value to your view.

1) Create a method on $scope to do the text replacement.

$scope.GetDataWithHtml = function() {
   return $scope.comment.data.replace(/\#word/gi, '<span>$1</span>');
};

2) In your <ul>, bind as follows:

<dul class="status_list">
  <li data-ng-repeat="comment in comments" class="status" ng-bind-html-unsafe="GetDataWithHtml()"></li>
</ul>

Upvotes: 0

Related Questions