-->

AngularJS Remove old $watchers when re-compiling d

2019-05-06 19:23发布

问题:

I have an AngularJS application that used to Build Pages dynamically (retrieve an XML from Server and by reading that XML building pages or forms) for an XML we have to build few pages all are related with each other and can be negative via 'Next' , 'Previous' buttons.

to implement that we have something like,

<div>
   <form name="myController.mainForm" novalidate>
      <div my-dynamic="myController.dynamicHtml"></div>
   </form>
</div>

herer myDynamic is directive, which deals with generated html and when we have to navigate to another page we generate new HTML for that page and assign it tomyController.dynamicHtml

and in that Directive I have something like this,

link: function postLink(scope, element, attrs) {
    scope.$watch(attrs.myDynamic, function (html) {
        element.html(html);
        $compile(element.contents())(scope);
    });
}

Now in each page I have number of input controls(or directives), and each have few bindings that that adds to number of watchers.

I have notice that if I negative navigate, to another page, watchers on previous pages not getting destroyed, until my-dynamic directive gets removed from scope.

What I need to do to make sure that watches on previous page gets destroyed when we again compile the HTML.

回答1:

Everytime the $compile service links something to a scope, it adds watchers. That is why directives such as ng-repeat, ng-switch, ng-view, ng-include and ng-if all create new child scopes. They link to the child scope and destroy that scope when destroying the compiled DOM. Use scope.$new and scope.$destroy.

link: function postLink(scope, element, attrs) {
    var newScope;
    scope.$watch(attrs.myDynamic, function (html) {
        if (newScope) {
            newScope.$destroy();
        };
        element.empty();
        if (html) {
            element.html(html);
            newScope = scope.$new()
            $compile(element.contents())(newScope);
        };
    });
}

This creates and destroys a child scope on changes.



回答2:

You can unwatch anything by assigning a variable to the watch:

var dynamicWatcher = scope.$watch(attrs.myDynamic, function (html) {
    element.html(html);
    $compile(element.contents())(scope);

    dynamicWatcher(); // unwatch
});

See the documentation at the return type:

Returns function()
Returns a deregistration function for this listener.