Ember.js - Verwenden eines Lenkstangenhelfers, um zu erkennen, dass eine Unteransicht gerendert wurde

8

Es gibt zahlreiche Fragen, die auf die eine oder andere Art fragen: "Wie mache ich etwas, nachdem ein Teil einer Ansicht gerendert wurde?" ( hier , hier und here nur um ein paar zu geben). Die Antwort lautet normalerweise:

  1. Verwenden Sie didInsertElement , um Code auszuführen, wenn eine Ansicht anfänglich gerendert wird.
  2. Verwenden Sie Ember.run.next(...) , um Ihren Code auszuführen nachdem die Änderungen der Ansicht geleert wurden, wenn Sie auf die erstellten DOM-Elemente zugreifen müssen.
  3. Verwenden Sie einen Beobachter in isLoaded oder eine ähnliche Eigenschaft, um etwas nach dem Laden der Daten zu tun, die Sie laden müssen.

Was daran irritiert, ist, dass es zu sehr ungeschickt aussehenden Dingen wie diesem führt:

%Vor%

Und das funktioniert nicht unbedingt, wenn Sie ember-data verwenden, da isLoaded möglicherweise bereits wahr ist (wenn der Datensatz bereits zuvor geladen wurde und nicht erneut vom Server angefordert wird). Also ist es schwierig, die Sequenzierung richtig zu machen.

Außerdem sehen Sie wahrscheinlich bereits isLoaded in Ihrer Ansichtsvorlage wie folgt:

%Vor%

und Wiederholung in Ihrem Controller scheint wie Duplikation.

Ich habe eine etwas neue Lösung gefunden, aber es muss entweder funktionieren oder ist eigentlich eine schlechte Idee ... jeder Fall könnte stimmen:

Ich habe einen kleinen Lenker-Helper namens {{fire}} geschrieben, der ein Ereignis mit einem benutzerdefinierten Namen auslöst, wenn die enthaltende Lenkervorlage ausgeführt wird (dh das sollte jedes Mal sein, wenn die Teilansicht erneut gerendert wird, richtig?).

Hier ist mein sehr früher Versuch:

%Vor%

was wie folgt verwendet wird:

%Vor%

Das funktioniert im Wesentlichen wie es ist, aber es hat ein paar Fehler, die ich schon kenne:

  1. Sie ruft die Methode auf dem Controller auf ... es wäre wahrscheinlich besser, fähig zu sein das "Ereignis" stattdessen an das Vorgänger-View-Objekt zu senden, vielleicht sogar, um das als Standard zu definieren Verhalten. Ich habe {{fire typeaheadHostDidRender target="view"}} ausprobiert und das hat nicht funktioniert. Ich kann noch nicht sehen, wie man die "aktuelle" Ansicht von dem bekommt, was in den Helfer gelangt ist, aber offensichtlich kann der {{view}} -Helfer es tun.
  2. Ich vermute, dass es einen formelleren Weg gibt, ein benutzerdefiniertes Ereignis auszulösen als das, was ich hier mache, aber das habe ich noch nicht gelernt. jQuery .trigger() scheint nicht auf Controller-Objekte zu funktionieren, obwohl es möglicherweise auf Ansichten funktioniert. Gibt es einen "Ember" Weg, dies zu tun?
  3. Es könnte Dinge geben, die ich nicht verstehe, wie ein Fall, in dem dieses Ereignis ausgelöst wird, aber die Ansicht nicht tatsächlich zum DOM hinzugefügt wird ...?

Wie Sie vielleicht raten können, verwende ich das Typeahead-Steuerelement von Bootstrap und muss es verbinden, nachdem das <input> gerendert wurde. Dies geschieht erst, nachdem mehrere verschachtelte {{#if}} Blöcke in meiner Vorlage als true ausgewertet wurden . Ich benutze auch jqPlot, so dass ich oft auf dieses Muster stoße. Dies scheint ein praktikables und nützliches Werkzeug zu sein, aber es könnte sein, dass mir etwas großes Bild fehlt, das diesen Ansatz dumm macht. Oder gibt es eine andere Möglichkeit, dies zu tun, die bei meinen Suchen nicht aufgetaucht ist?

Kann jemand diesen Ansatz für mich verbessern oder mir sagen, warum es eine schlechte Idee ist?

AKTUALISIEREN

Ich habe ein paar der Bits rausgefunden:

  1. Ich kann vielleicht die erste "echte" Ansicht mit options.data.view.get('parentView') ... erhalten, aber vielleicht hätte ich das nicht so einfach gehalten.
  2. Sie können tatsächlich einen jQuery-Style obj.trigger(evtName) für jedes beliebige Objekt erstellen ... aber das Objekt muss Ember.Evented mixin erweitern! Ich nehme an, es ist der richtige Weg, diese Art von Ereignis in Ember zu senden. Stellen Sie nur sicher, dass das beabsichtigte Ziel Ember.Evented (Ansichten bereits) erweitert.

Hier ist die verbesserte Version:

%Vor%

Jetzt fehlt mir nur noch die Frage, wie ich das beabsichtigte Ziel einbringen kann (z. B. den Controller oder die Ansicht - der obige Code versucht zu erraten). Oder herausfinden, ob es ein unerwartetes Verhalten gibt, das das ganze Konzept durchbricht.

Irgendwelche anderen Eingaben?

    
S'pht'Kr 07.12.2012, 09:56
quelle

1 Antwort

16

AKTUALISIERT

Aktualisiert für Ember 1.0 final, ich verwende diesen Code derzeit in Ember 1.3.1.

Okay, ich denke, ich habe alles herausgefunden. Hier ist der "komplette" Lenkerhelfer:

%Vor%

Ich habe den Namen von {{fire}} in {{trigger}} geändert, damit er besser der Ember.Evented / jQuery-Konvention entspricht. Dieser aktualisierte Code basiert auf dem integrierten Hilfsprogramm Ember {{action}} und sollte in der Lage sein, jedes target="..." Argument in Ihrer Vorlage zu akzeptieren, genauso wie {{action}} . Wo es sich von {{action}} unterscheidet (abgesehen davon, dass es automatisch ausgelöst wird, wenn der Template-Abschnitt gerendert wird):

  1. Sendet das Ereignis standardmäßig an die Ansicht. Das Senden an die Route oder den Controller würde in der Regel nicht so viel Sinn ergeben, da dies wahrscheinlich in erster Linie für Ansichten-zentrierte Aktionen verwendet werden sollte (obwohl ich es oft zum Senden von Ereignissen an einen Controller verwende).
  2. Verwendet Ember.Evented-Stil-Ereignisse. Um also ein Ereignis an ein beliebiges Nicht-View-Objekt (einschließlich eines Controllers) zu senden, muss das Objekt Ember.Evented erweitern, und muss ein Listener registriert sein. (Um es klar zu sagen, es ruft nichts im actions: {…} Hash!)
  3. auf

Beachten Sie, dass Sie, wenn Sie ein Ereignis an eine Instanz von Ember.View senden, lediglich eine Methode mit dem gleichen Namen implementieren müssen (siehe Dokumente , Code ). Wenn Ihr Ziel jedoch keine Ansicht ist (z. B. ein Controller), müssen Sie einen Listener für das Objekt mit obj.on('evtName', function(evt){...}) oder der Erweiterung Function.prototype.on registrieren.

Hier ist ein Beispiel aus der Praxis. Ich habe eine Ansicht mit der folgenden Vorlage, die Ember und Bootstrap verwendet:

%Vor%

Ich musste wissen, wann dieses Element im DOM verfügbar war, also konnte ich einen Typeahead anhängen:

%Vor%

Also habe ich einen {{trigger}} Helfer in den selben Block geschrieben:

%Vor%

Und dann didRenderSubjectPicker in meiner View-Klasse implementiert:

%Vor%

Fertig! Jetzt wird der Typeahead verdrahtet, wenn (und nur wenn) der Unterabschnitt der Vorlage schließlich gerendert wird. Beachten Sie den Unterschied im Dienstprogramm, didInsertElement wird verwendet, wenn die main (oder vielleicht "konkrete" ist der richtige Begriff) Ansicht gerendert wird, während didRenderSubjectPicker wird ausgeführt, wenn der Unterabschnitt der Ansicht wird gerendert.

Wenn ich das Ereignis stattdessen direkt an den Controller senden wollte, ändere ich einfach die Vorlage, um zu lesen:

%Vor%

und mache das in meinem Controller:

%Vor%

Fertig!

Der einzige Vorbehalt besteht darin, dass dies wieder passieren kann , wenn der Ansichtsunterabschnitt bereits auf dem Bildschirm angezeigt wird (z. B. wenn eine übergeordnete Ansicht erneut gerendert wird). Aber in meinem Fall ist das Ausführen der typeahead-Initialisierung immer noch in Ordnung, und es wäre ziemlich einfach, wenn nötig zu erkennen und zu codieren. Und dieses Verhalten kann in einigen Fällen erwünscht sein.

Ich gebe diesen Code als Public Domain heraus, keine Garantie oder Haftung, egal wie. Wenn Sie das verwenden möchten oder die Ember-Leute es in die Baseline aufnehmen wollen, gehen Sie weiter! (Ich persönlich denke, das wäre eine großartige Idee, aber das ist nicht überraschend.)

    
S'pht'Kr 13.12.2012, 10:28
quelle

Tags und Links