2017-06-29 2 views
0

ich eine Richtlinie habe, sein Rückruf wie folgt aussieht:noch zerstörte Steuerungsbereich Rundfunk AngularJS

function Callback(){ 
    return { 
     templateUrl: 'somePath', 
     scope: true, 
     link: function(scope, el) { 
     scope.cancel = function(){ 
      el.remove() 
      scope.$destroy() 
     } 
     }, 
     controller: 'someController', 
     controllerAs: 'vm' 
    } 
    } 

Die Link-Methode fügt nur ein Abbrechen Methode, die die Richtlinie aus dem DOM entfernt.

In der Richtlinie Controller für ein Ereignis Ich höre:

$rootScope.$on('parent', function(){ 
    someService.addToArray(someData) 
}) 

Diese Methode schiebt nur Daten in ein Array.

In einem übergeordneten Controller und anzeigen, wo diese Richtlinie verwendet wird, feuere ich tatsächlich die Übertragung. Ein Teil der übergeordneten Steuerung:

var vm = this 
vm.broadcastEvent = broadcastEvent  
function broadcastEvent(){ 
    $rootScope.$broadcast('someEvent', 'someData') 
} 

Und in der Ansicht ich einige klickbare div haben, die diese Methode abfeuert.

Es funktioniert gut, hört die Richtlinie die Übertragung und fügt Daten zu einem Array, bevor ich das Element entfernen und den Bereich zerstören.

Das Problem ist, nachdem ich .cancel aufrufen, wird das Element entfernt und vermutlich wird der Bereich zerstört, aber es fügt noch Daten zum Array hinzu. Fehle ich etwas darüber, wie scope.$destroy() funktioniert?

Ich kann das Verhalten, das ich will, durch denegistrieren die $on bekommen, muss ich nur so oder so tun? Ich denke, die Frage ist, zerstört das Zerstören der Controller-Bereich $on in ihm definiert, oder müssen Sie sicherstellen, dass Sie explizit die Registrierung entfernen, bevor Sie den Bereich zu zerstören.

Antwort

1

Die Listener-Funktion auf $ rootScope registriert ist, und wird nach der Direktive $ Umfang überleben wird zerstört:

Dieser Controller muss die Deregister-Funktion speichern, die durch den Aufruf von $ rootScope zurückgegeben wird .$ Auf Methode:

this.deregister = $rootScope.$on('parent', function listener(){ 
    someService.addToArray(someData) 
}) 

Die Abbrechen-Funktion benötigt die Deregistrierung Funktion aufzurufen:

link: function(scope, el) { 
    scope.cancel = function(){ 
     el.remove() 
     scope.$destroy() 
     scope.vm.deregister() 
    } 
    }, 
    controller: 'someController', 
    controllerAs: 'vm' 

sollte nicht das Abmelde geschehen, bevor der Umfang zerstört wird?

Es spielt keine Rolle. Wie Sie festgestellt haben, wird der Listener in $ rootScope registriert und in einem Array unter $ rootScope (speziell $rootScope.$$listeners) gespeichert. Es wird von $rootScope.$$listeners durch Aufrufen der Deregistrierungsfunktion entfernt.

Es ist die Natur von objektorientierten Laufzeiten wie JavaScript, dass ein Objekt nur dann aus dem Speicher entfernt wird (Garbage Collection), wenn alle Referenzen auf diese Objekte zerstört sind. Da ein Verweis auf die Listener-Funktion in $ rootScope gespeichert ist, überlebt er (und sein Ausführungskontext).

Wenn der Listener in der Direktive $ scope registriert worden wäre, würde er automatisch entfernt, wenn der Bereich zerstört wurde.

+0

yep, das ist genau das, was ich getan habe, und es machte mehr Sinn, als ich die Frage schrieb. Danke wie immer @georgeawg! –

+0

sollte der Deregister nicht passieren, bevor der Bereich zerstört wird? –

0

Ich bin mir nicht sicher, dass der scope.$destroy() richtig aufgerufen wird.

Wie es in dem $scope doc geschrieben hat:

Entfernt den aktuellen Bereich (und alle seine Kinder) aus dem übergeordneten Umfang. [...] Beachten Sie, dass es in AngularJS auch ein Ereignis $ destroy jQuery gibt, das zum Bereinigen von DOM-Bindungen verwendet werden kann, bevor ein Element aus dem DOM entfernt wird.

Also, ich glaube, Sie sollten es gerne tun:

link: function(scope, el) { 
     el.on('$destroy', function() { 
      scope.$destroy(); 
     }); 

     scope.cancel = function(){ 
      el.remove(); 
     } 
     } 

Sag mir, wenn es Ihr Problem löst

Verwandte Themen