2017-10-04 6 views
7

Kurz gesagt: Ich mag das Ergebnis .bind als Argument in einem eigenen AufrufEntfernen einen Eventhandler in dem Handler selbst

var bound = foo.bind(this,bound); 

binden, weil ich nicht sicher bin, wie sonst mein Problem zu lösen.

Das Problem:

Ich habe ein Element, das auf einer Reihe von anderen Elementen abhängig ist. Sobald eines dieser Elemente entfernt wird, möchte ich das abhängige Element entfernen und alle Listener entfernen, die auf die Abhängigkeiten platziert wurden.

Ich habe Probleme, die Eventhandler der anderen Abhängigkeiten zu entfernen. Ich versuche, Bind zu verwenden, aber da die Handler-Funktion derjenige ist, der die Listener entfernt, finde ich, dass ich das Ergebnis des bind() Aufrufs in seinem eigenen Aufruf als ein Argument binden müsste. Das funktioniert natürlich nicht.

Der Bind-Call-Balg bindet die ungebundene Version von 'Handler' als Parameter und somit funktioniert removeEventListener nicht, da es sich um eine andere Kopie der Funktion handelt.

Die Frage ist: kann ich Bind verwenden, um dies zu tun und/oder wie kann ich das sonst lösen?

Ich verwende eventemitter3, aber es sollte für jede Ereignisbibliothek gleich sein.

setHandlers(dependentItem,dependencies) 
{ 
    var handler = this.onDependencyRemoved; 
    handler = handler.bind(this,dependentItem,dependencies,handler);//bind itself as third argument 
    dependencies.forEach(dependency => { 
     dependency.addEventListener("removed",handler); 
    }); 
} 
onDependencyRemoved(dependentItem,dependencies,handler) 
{ 
    dependentItem.remove(); 
    dependencies.forEach(dependency => { 
      dependency.removeEventListener("removed",handler); 
    }); 
} 

edit:

Komplette Arbeits Beispiel in NodeJS auszuführen:

const EventEmitter = require('events'); 
//const EventEmitter = require('eventemitter3'); 

class MyEmitter extends EventEmitter { 
    remove() { 
     console.log("I'm being removed, this should happen only once"); 
    } 
} 
var dependent = new MyEmitter(); 
var dependencies = [new MyEmitter(),new MyEmitter()]; 

var handler = (e) => removeHandler(dependencies,dependent,handler); 

dependencies.forEach(dependency => dependency.once('removed',handler)); 

var removeHandler = function(dependencies,dependent,handler) { 
    //remove the dependent object because one of the dependencies was removed 
    dependent.remove(); 
    //remove the listeners from all of the dependencies 
    dependencies.forEach(dependency => { 
     console.log('before removing: '+dependency.listeners('removed').length); 
     dependency.removeListener('removed',handler); 
     console.log('after removing: '+dependency.listeners('removed').length); 
    }); 
} 

//should remove the dependent object 
dependencies[0].emit("removed"); 
//should not do anything anymore since the listeners are removed 
dependencies[1].emit("removed"); 
+0

Verwenden Sie [Ereignisdelegierung] (https://Stackoverflow.com/a/1688293/402037) und fügen Sie _one_ handler zu einem übergeordneten Element hinzu. – Andreas

+0

@Andreas Ich bin in node.js. Die Elemente sind Modelle/ES6-Klasseninstanzen, keine DOM-Elemente. – Flion

Antwort

7

Sie können dies mit bind nicht tun, aber Sie können mit einem Verschluss diese relativ einfach zu tun - entweder direkt für die zu bindende Funktion oder in Ihrer eigenen Hilfsfunktion ähnlich bind. Es ist so einfach wie

const handler = (e) => this.onDependencyRemoved(dependentItem, dependencies, handler, e); 

Ich bin nicht sicher, aber warum diese beiden Funktionen Methoden von irgendetwas sind; sie sehen eher statisch aus. Es macht sinnvoll, sie Methoden der dependentItem zu machen, in diesem Fall müssen die Argumente und sogar die ganze handler nicht in Closure-Variablen gespeichert werden, sondern könnten Instanzeigenschaften im Konstruktor initialisiert werden.

+0

mit dem Verschluss funktioniert es immer noch nicht. Wenn ich den Ereignis-Listener lösche, stimmt der einmal registrierte Handler nicht mit ''==' 'mit dem von 'onDependencyRemoved' verwendeten Handler überein. Ich habe die Frage mit dem Abschluss-Setup bearbeitet. – Flion

+0

@Flion Ich kann nicht reproduzieren, Ihr Code sollte funktionieren. Ich glaube, Sie haben entweder Ihren vollständigen Code nicht angezeigt oder das Problem ist woanders. Kannst du ein [mcve] machen? Ich bin auch neugierig, wie Sie '===' "* gegen die Handler-Funktion überprüfen können, sobald sie mit addEventListener *" gespeichert wurde, da 'addEventListener' den Speicher nicht verfügbar macht. – Bergi

+1

yeah Ich habe gerade ein minimales vollständiges Beispiel erstellt und es hat funktioniert in Ordnung sowohl mit dem nativen EventEmitter von node.js als auch mit der Bibliothek 'eventEmitter3'. Mir wurde klar, dass removeEventListener nicht immer aufgerufen wird, wenn etwas entfernt wird, weil das Element, das das Ereignis 'removed' ausgelöst hat, bereits entfernt hat, weil ich 'once' verwende. Tnx für die Hilfe! Ich werde morgen Kopfgeld geben. Dies war ein wichtiges Thema für mich und ich wusste nie, dass eine einfache Schließung einen Wert in seiner eigenen Funktion wiederverwenden könnte, wie Sie gezeigt haben. – Flion

6

Es gibt bessere Möglichkeiten, Ihr Problem zu lösen, die andere erwähnt haben. Allerdings gibt es ein grundlegenderes Problem mit dem Code:

var bound = foo.bind(this,bound); 

Der Wert bound im Code, die zum Zeitpunkt der Ausführung, ist undefined. Dies ist das Äquivalent von nur foo.bind(this) aufrufen, was wahrscheinlich nicht das ist, was Sie wollen.

+0

Ich bin mir dessen bewusst, ich habe es nur geschrieben, um zu versuchen, zu erklären, was ich versucht habe zu tun. – Flion

Verwandte Themen