Was ist der richtige Weg, um zwischen Controllern zu kommunizieren?
Ich benutze derzeit einen schrecklichen Fudge mit window
:
function StockSubgroupCtrl($scope, $http) {
$scope.subgroups = [];
$scope.handleSubgroupsLoaded = function(data, status) {
$scope.subgroups = data;
}
$scope.fetch = function(prod_grp) {
$http.get('/api/stock/groups/' + prod_grp + '/subgroups/').success($scope.handleSubgroupsLoaded);
}
window.fetchStockSubgroups = $scope.fetch;
}
function StockGroupCtrl($scope, $http) {
...
$scope.select = function(prod_grp) {
$scope.selectedGroup = prod_grp;
window.fetchStockSubgroups(prod_grp);
}
}
Antworten:
Bearbeiten : Das in dieser Antwort angesprochene Problem wurde in angle.js Version 1.2.7 behoben .
$broadcast
Jetzt wird das Sprudeln über nicht registrierte Bereiche vermieden und läuft genauso schnell wie $ emit.So, jetzt können Sie:
$broadcast
aus dem$rootScope
$on
dem lokalen$scope
, der über das Ereignis wissen mussOriginalantwort unten
Ich rate dringend, nicht
$rootScope.$broadcast
+$scope.$on
, sondern$rootScope.$emit
+ zu verwenden$rootScope.$on
. Ersteres kann schwerwiegende Leistungsprobleme verursachen, wie von @numan angesprochen. Das liegt daran, dass das Ereignis durch alle Bereiche sprudelt .Letzteres (mit
$rootScope.$emit
+$rootScope.$on
) leidet jedoch nicht darunter und kann daher als schneller Kommunikationskanal verwendet werden!Aus der Winkeldokumentation von
$emit
:Da oben kein Bereich
$rootScope
vorhanden ist, tritt kein Sprudeln auf. Es ist absolut sicher,$rootScope.$emit()
/$rootScope.$on()
als EventBus zu verwenden.Es gibt jedoch ein Problem, wenn Sie es in Controllern verwenden. Wenn Sie direkt
$rootScope.$on()
von einem Controller aus eine Bindung herstellen, müssen Sie die Bindung selbst bereinigen, wenn Ihr lokaler$scope
Server zerstört wird. Dies liegt daran, dass Controller (im Gegensatz zu Diensten) über die Lebensdauer einer Anwendung mehrmals instanziiert werden können, was dazu führen würde, dass Bindungen summiert werden und überall Speicherlecks entstehen :)Um austragen, hört nur auf
$scope
‚s$destroy
Ereignis und dann die Funktion aufrufen , die von zurückgegeben wurde$rootScope.$on
.Ich würde sagen, das ist nicht wirklich eine eckenspezifische Sache, da es auch für andere EventBus-Implementierungen gilt, dass Sie Ressourcen bereinigen müssen.
In diesen Fällen können Sie Ihnen jedoch das Leben erleichtern. Zum Beispiel könnten Sie einen Affen-Patch erstellen
$rootScope
und ihm einen geben$onRootScope
, der Ereignisse abonniert, die auf dem$rootScope
ausgegeben werden, aber auch den Handler direkt bereinigt, wenn der lokale$scope
Server zerstört wird.Der sauberste Weg, um Affen zu patchen
$rootScope
, um eine solche$onRootScope
Methode bereitzustellen , wäre durch einen Dekorateur (ein Run-Block wird es wahrscheinlich auch gut machen, aber pssst, sag es niemandem)Um sicherzustellen, dass die
$onRootScope
Eigenschaft beim Aufzählen nicht unerwartet angezeigt wird, verwenden$scope
wirObject.defineProperty()
und setzenenumerable
auffalse
. Denken Sie daran, dass Sie möglicherweise eine ES5-Unterlegscheibe benötigen.Mit dieser Methode kann der Controller-Code von oben vereinfacht werden, um:
Als Endergebnis all dessen rate ich Ihnen dringend,
$rootScope.$emit
+ zu verwenden$scope.$onRootScope
.Übrigens versuche ich, das Winkel-Team davon zu überzeugen, das Problem innerhalb des Winkelkerns anzugehen. Hier findet eine Diskussion statt: https://github.com/angular/angular.js/issues/4574
Hier ist ein jsperf, das zeigt, wie viel Perfektion
$broadcast
in einem anständigen Szenario mit nur 100 Sekunden auf den Tisch kommt$scope
.http://jsperf.com/rootscope-emit-vs-rootscope-broadcast
quelle
Die beste Antwort hier war eine Umgehung eines Angular-Problems, das nicht mehr existiert (zumindest in Versionen> 1.2.16 und "wahrscheinlich früher"), wie @zumalifeguard erwähnt hat. Aber ich lese all diese Antworten ohne eine tatsächliche Lösung.
Es scheint mir, dass die Antwort jetzt sein sollte
$broadcast
aus dem$rootScope
$on
dem lokalen$scope
, der über das Ereignis wissen mussAlso zu veröffentlichen
Und abonnieren
Plunker
Controller As
SyntaxWenn Sie den Listener lokal registrieren
$scope
, wird er automatisch von$destroy
selbst zerstört, wenn der zugehörige Controller entfernt wird.quelle
controllerAs
Syntax verwendet werden kann? Ich konnte$rootScope
im Abonnenten das Ereignis abhören, war aber nur neugierig, ob es ein anderes Muster gab.$scope
explizit injizieren . John Papa schreibt über Ereignisse, die eine "Ausnahme" von seiner üblichen Regel darstellen,$scope
sich von seinen Controllern fernzuhalten (ich verwende Anführungszeichen, weil sie, wie er immerController As
noch erwähnt$scope
, direkt unter der Motorhaube liegen).controller as
wie gewünscht mit einer Syntaxalternative aktualisiert . Ich hoffe das hast du gemeint.Verwenden von $ rootScope. $ Broadcast und $ scope. $ On für eine PubSub-Kommunikation.
Siehe auch diesen Beitrag: AngularJS - Kommunikation zwischen Controllern
quelle
$rootScope
und$watch
. Ich bin mir nicht sicher, ob das eine Verbesserung ist.Da defineProperty ein Problem mit der Browserkompatibilität aufweist, können wir über die Verwendung eines Dienstes nachdenken.
und verwenden Sie es in Controller wie folgt:
Controller 1
Controller 2
quelle
GridLinked hat eine PubSub- Lösung veröffentlicht, die ziemlich gut gestaltet zu sein scheint. Den Service finden Sie hier .
Auch ein Diagramm ihres Dienstes:
quelle
Die tatsächliche Verwendung von Emit und Broadcast ist ineffizient, da das Ereignis in der Bereichshierarchie auf und ab sprudelt, was für eine komplexe Anwendung leicht zu einer Leistungsminderung führen kann.
Ich würde vorschlagen, einen Dienst zu nutzen. So habe ich es kürzlich in einem meiner Projekte implementiert - https://gist.github.com/3384419 .
Grundidee - Registrieren Sie einen Pubsub / Event-Bus als Service. Fügen Sie dann diesen Eventbus ein, wo immer Sie Events / Themen abonnieren oder veröffentlichen müssen.
quelle
$rootScope.$emit()
nur Blasen nach oben blasen. Da es jedoch keinen Spielraum darüber$rootScope
gibt, gibt es nichts zu befürchten. Wenn Sie also nur verwenden$rootScope.$emit()
und$rootScope.$on()
einen schnellen systemweiten EventBus haben.$rootScope.$on()
in Ihrem Controller die Ereignisbindung bereinigen müssen, da sie sich sonst summieren, wenn jedes Mal, wenn der Controller instanziiert wird, eine neue erstellt wird und dies nicht der Fall ist werden automatisch für Sie zerstört, da Sie$rootScope
direkt an binden .Mit get- und set-Methoden innerhalb eines Dienstes können Sie sehr einfach Nachrichten zwischen Controllern übertragen.
In HTML HTML können Sie dies überprüfen
quelle
In Bezug auf den ursprünglichen Code möchten Sie anscheinend Daten zwischen Bereichen austauschen. Um entweder Daten oder Status zwischen $ scope zu teilen, schlagen die Dokumente die Verwendung eines Dienstes vor:
Ref: Angular Docs Link hier
quelle
Ich habe tatsächlich begonnen, Postal.js als Nachrichtenbus zwischen Controllern zu verwenden.
Als Nachrichtenbus bietet er viele Vorteile, z. B. Bindungen im AMQP-Stil, die Art und Weise, wie Post W / iFrames und Web-Sockets integrieren kann, und vieles mehr.
Ich habe einen Dekorateur benutzt, um die Post einzurichten
$scope.$bus
...Hier ist ein Link zu einem Blog-Beitrag zum Thema ...
http://jonathancreamer.com/an-angular-event-bus-with-postal-js/
quelle
So mache ich das mit Factory / Services und Simple Dependency Injection (DI) .
quelle
Mir hat gefallen, wie
$rootscope.emit
die Interkommunikation erreicht wurde. Ich schlage die saubere und leistungsfähige Lösung vor, ohne den globalen Raum zu verschmutzen.quelle
Hier ist der schnelle und schmutzige Weg.
Hier ist eine Beispielfunktion, die in einem der Geschwister-Controller hinzugefügt werden kann:
und hier ist natürlich dein HTML:
quelle
$rootScope
?Starten Sie Winkel 1.5 und seinen komponentenbasierten Entwicklungsfokus. Die empfohlene Art der Interaktion von Komponenten besteht in der Verwendung der Eigenschaft 'require' und in Eigenschaftsbindungen (Eingabe / Ausgabe).
Eine Komponente würde eine andere Komponente (z. B. die Stammkomponente) benötigen und einen Verweis auf ihren Controller erhalten:
Sie können dann die Methoden der Stammkomponente in Ihrer untergeordneten Komponente verwenden:
Dies ist die Root-Komponenten-Controller-Funktion:
Hier ist eine vollständige architektonische Übersicht: Komponentenkommunikation
quelle
Sie können auf diese Hallo-Funktion überall im Modul zugreifen
Controller eins
zweite Steuerung
Mehr Infos hier
quelle
Ich werde einen Dienst erstellen und eine Benachrichtigung verwenden.
Da der Benachrichtigungsdienst zu jedem Zeitpunkt ein Singleton ist, sollte er in der Lage sein, persistente Daten für alle bereitzustellen.
Hoffe das hilft
quelle
Sie können den integrierten AngularJS-Dienst verwenden
$rootScope
und diesen Dienst in beide Controller einfügen. Sie können dann auf Ereignisse warten, die für das $ rootScope-Objekt ausgelöst werden.$ rootScope bietet zwei aufgerufene Ereignis-Dispatcher,
$emit and $broadcast
die für das Versenden von Ereignissen verantwortlich sind (möglicherweise benutzerdefinierte Ereignisse) und die$rootScope.$on
Funktion zum Hinzufügen eines Ereignis-Listeners verwenden.quelle
Sie sollten den Dienst verwenden, da der
$rootscope
Zugriff von der gesamten Anwendung aus erfolgt und die Last erhöht wird, oder Sie können die Rootparams verwenden, wenn Ihre Daten nicht mehr sind.quelle
quelle
Sie können dies tun, indem Sie Winkelereignisse verwenden, die $ emit und $ Broadcast sind. Nach unserem Kenntnisstand ist dies der beste, effizienteste und effektivste Weg.
Zuerst rufen wir eine Funktion von einem Controller aus auf.
Sie können auch $ rootScope anstelle von $ scope verwenden. Verwenden Sie Ihren Controller entsprechend.
quelle