TechCrunch TechCrunch - 6 months ago 22
AngularJS Question

How to watch ng-html-bind from a directive?

I'm trying to watch the content of ng-html-bind and modify the div content to auto link all hyperlinks in the div since the original content will not have hyperlink html.

Here is the plunker

Here is the directive

app.directive('autolink', ['$compile', '$timeout', function ($compile, $timeout) {
return {
restrict: 'EA',
replace: true,
link: function (scope, element, attrs) {

$timeout(function () {
var text = element[0].innerHTML;
var linkTypes = ["http://", "https://"];
linkTypes.forEach(function (linkType) {
var startSpace = 0;
while (startSpace >= 0) {
text = element[0].innerHTML;
var locationOfHttp = text.indexOf(linkType, startSpace);
if (locationOfHttp < 0) break;
var locationOfSpace = text.indexOf(" ", locationOfHttp);
var textAfter = "";
if (locationOfSpace < 0) {
locationOfSpace = text.length;
} else {
textAfter = text.substring(locationOfSpace, text.length);
}
var linkUrl = text.substring(locationOfHttp, locationOfSpace);
var htmlText = text.substring(0, locationOfHttp) + '<a href="' + linkUrl + '">' + linkUrl + '</a>' + textAfter;
element[0].innerHTML = htmlText;
startSpace = (text.substring(0, locationOfHttp) + '<a href="' + linkUrl + '">' + linkUrl + '</a>').length - 1;
}
});
scope.$apply();
console.log("autolink");

}, 1);
},
};
}]);


My directive is working when the page loads but not when I click on the change URL, div is not auto linking. How do I watch for the change and run the directive on change ?

Answer

So you can use scope.$watch() to watch for the change on a scope variable, run it through your link creating function, and then add it back in to the element.

Here is a fork of your plunk that does just that.

I had to change the ng-bind-html to be unlinked-html by way of using an isolate scope (Directive isolate scope), which allows your new text with the urls in it to be passed to the directive, where the scope.$watch takes over.

The new html:

<div unlinked-text="parseResult(details)" autolink></div>

Here is the code for the directive below:

app.directive('autolink', ['$compile', '$timeout', function ($compile, $timeout) {
        return {
            restrict: 'EA',
            replace: false,
            // isolate scope below the html attribute 
            // unlinked-text is automatically translated 
            // to the scope variable unlinkedText by angular.
            scope: {
              unlinkedText: '='
            }, 
            // added a template that uses ng-bind-html with
            // your new, link-ified text
            template: '<span ng-bind-html="text"></span>',
            link: function (scope, element, attrs) {
              scope.text = scope.unlinkedText;
              function addLinks(str) {
                 var text = str;
                  console.log(text.match(/https?:\/\/\w*/));
                  var links_parsed = text
                  .replace(/https?:\/\/[\w\.]*/g, 
                          function(substr) { 
                            return '<a href="' + substr + '">' + substr + '</a>'; 

                          });
                  return links_parsed;
              }
              // Still using timeout for initial run of addLinks
              $timeout(function() { 
                scope.text = addLinks(scope.text);
              },0)
              // scope watches unlinkedText variable
              scope.$watch('unlinkedText', function(newVal, oldVal) {
                if(newVal !== oldVal) { // if variable has changed...
                  scope.text = addLinks(newVal); // ...runs addLinks() again
                }
              } );


            }
        };
    }]);
Comments