AngularJS : Watch element.html() in a directive

2019-04-02 22:33发布

问题:

I am looking to create a mardown directive (restrict A) which would make me able to use same recipient for ng-view. So I would basically load only .md files in views and apply my function on its content each time ng-view change. So :

index.html

<div markdown ng-view></div>

with two views containing, let say, view1.md

#That should be h1

and view2.md

##That should be h2, no ?

My actual code is

'use strict';
angular.module('btford.markdown', []).
  directive('markdown', function () {
    var converter = new Showdown.converter();

    return {
        restrict: 'A',
        link: function (scope, element, attrs) {

            scope.$watch(element.html(), function(value) {
                    var htmlText = converter.makeHtml(element.html());
                    element.html(htmlText);
            });

            var htmlText = converter.makeHtml(element.text());
            element.html(htmlText);
        }
    }
});

回答1:

The first param of watch can be a function, return any value you want including your $element.html(). You can even do a combination of data

$scope.$watch(
    function() { return $element.attr("abc") + $scope.variable + someinternalvar; },
    function(newVal, oldVal) { doTheStuff(); }
);

Obviously the more intense the data you put in here the slower your watches will be. Use caution.

-- FYI

You should clean up your watchers, create an array and push the results of $scope.$watch into that array. Then on the $destroy message remove them. Also remember to unbind events as they will cause eventual performance issues as scopes are created & destroyed.

$document.bind('click', clickMe);
$(window).on("resize", winResize);

var watches = []

watches.push($scope.$watch("thing", function() { Thing(); }));

$scope.$on("$destroy", function () {
    for (var i in watches) watches[i]();
    $document.unbind('click', clickMe);
    $(window).off("resize", winResize);
});

-- EDIT 2016-07-14

Just to add, cleaning up scope watchers is not needed as they are already processed internally, however rootScope, parent, etc. you should absolutely cleanup.



回答2:

It may be cleaner for you to use the $stateChangeSuccess event inside your directive rather than setting your own $watch. Try adding a callback function to the $stateChangeSuccess event, this should trickle down to the scope of your directive.

'use strict';

angular.module('btford.markdown', []).
  directive('markdown', function () {
    var converter = new Showdown.converter();

    return {
        restrict: 'A',
        link: function (scope, element, attrs) {

            // When the state is change to, or reloaded...
            scope.$on('$stateChangeSuccess', function () {
                var htmlText = converter.makeHtml(element.text());
                element.html(htmlText);
            });
        }
    }
});


回答3:

You can only watch variables on your scope.

scope.foo = 'bar';
scope.$watch('foo', function(newValue) {
  // Code to execute here
});

If you want to monitor the changes of DOM elements you need to do this on your own.