Quelle est la bonne façon de communiquer entre les contrôleurs?
J'utilise actuellement un horrible fudge impliquant 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);
}
}
Réponses:
Edit : Le problème abordé dans cette réponse a été résolu dans angular.js version 1.2.7 .
$broadcast
évite désormais de se propager sur des étendues non enregistrées et s'exécute aussi vite que $ emit.Vous pouvez donc désormais:
$broadcast
partir du$rootScope
$on
le local$scope
qui a besoin de connaître l'événementRéponse originale ci-dessous
Je conseille fortement de ne pas utiliser
$rootScope.$broadcast
+$scope.$on
mais plutôt$rootScope.$emit
+$rootScope.$on
. Le premier peut entraîner de graves problèmes de performances, comme l'a soulevé @numan. En effet, l'événement bouillonnera dans tous les domaines.Cependant, ce dernier (en utilisant
$rootScope.$emit
+$rootScope.$on
) n'en souffre pas et peut donc être utilisé comme canal de communication rapide!De la documentation angulaire de
$emit
:Puisqu'il n'y a pas de portée ci
$rootScope
- dessus , il n'y a pas de bouillonnement. Il est totalement sûr d'utiliser$rootScope.$emit()
/$rootScope.$on()
comme EventBus.Cependant, il existe un problème lors de son utilisation à partir de contrôleurs. Si vous vous connectez directement à
$rootScope.$on()
partir d'un contrôleur, vous devrez nettoyer la liaison vous-même lorsque votre section locale sera$scope
détruite. En effet, les contrôleurs (contrairement aux services) peuvent être instanciés plusieurs fois au cours de la durée de vie d'une application, ce qui entraînerait la synthèse des liaisons, créant éventuellement des fuites de mémoire partout :)Pour annuler l' enregistrement, il suffit d' écouter sur votre
$scope
de »$destroy
l'événement, puis appeler la fonction qui a été renvoyée par$rootScope.$on
.Je dirais que ce n'est pas vraiment une chose spécifique angulaire, car cela s'applique également aux autres implémentations EventBus, que vous devez nettoyer les ressources.
Cependant, vous pouvez vous faciliter la vie dans ces cas. Par exemple, vous pouvez corriger le singe
$rootScope
et lui donner un$onRootScope
qui s'abonne aux événements émis sur le$rootScope
mais nettoie également directement le gestionnaire lorsque le local$scope
est détruit.La façon la plus propre de patcher le singe
$rootScope
pour fournir une telle$onRootScope
méthode serait de passer par un décorateur (un bloc d'exécution le fera probablement très bien aussi mais pssst, ne le dites à personne)Pour vous assurer que la
$onRootScope
propriété ne s'affiche pas de manière inattendue lors de l'énumération,$scope
nous utilisonsObject.defineProperty()
et définissonsenumerable
surfalse
. Gardez à l'esprit que vous pourriez avoir besoin d'une cale ES5.Avec cette méthode en place, le code du contrôleur ci-dessus peut être simplifié pour:
Donc, comme résultat final de tout cela, je vous conseille fortement d'utiliser
$rootScope.$emit
+$scope.$onRootScope
.Btw, j'essaie de convaincre l'équipe angulaire de résoudre le problème dans le noyau angulaire. Il y a une discussion en cours ici: https://github.com/angular/angular.js/issues/4574
Voici un jsperf qui montre combien un impact de perf
$broadcast
apporte à la table dans un scénario décent avec seulement 100$scope
.http://jsperf.com/rootscope-emit-vs-rootscope-broadcast
la source
La meilleure réponse ici était un contournement d'un problème angulaire qui n'existe plus (au moins dans les versions> 1.2.16 et "probablement plus tôt") comme @zumalifeguard l'a mentionné. Mais il me reste à lire toutes ces réponses sans solution réelle.
Il me semble que la réponse devrait maintenant être
$broadcast
partir du$rootScope
$on
le local$scope
qui a besoin de connaître l'événementDonc pour publier
Et abonnez-vous
Plunkers
Controller As
syntaxeSi vous enregistrez l'auditeur sur le plan local
$scope
, il sera automatiquement détruit par$destroy
lui - même quand on retire le contrôleur associé.la source
controllerAs
syntaxe? J'ai pu utiliser$rootScope
l'abonné pour écouter l'événement, mais j'étais simplement curieux de savoir s'il y avait un modèle différent.$scope
explicitement. John Papa écrit que les événements sont une "exception" à sa règle habituelle de garder$scope
"à distance " ses contrôleurs (j'utilise des guillemets car comme il le mentionneController As
toujours$scope
, c'est juste sous le capot).controller as
alternative de syntaxe comme demandé. J'espère que c'est ce que tu voulais dire.Utilisation de $ rootScope. $ Broadcast et $ scope. $ On pour une communication PubSub.
Voir également cet article: AngularJS - Communiquer entre les contrôleurs
la source
$rootScope
et$watch
. Je ne suis pas sûr que ce soit une amélioration.Étant donné que defineProperty a un problème de compatibilité avec le navigateur, je pense que nous pouvons penser à utiliser un service.
et l'utiliser dans un contrôleur comme celui-ci:
contrôleur 1
contrôleur 2
la source
GridLinked a publié une solution PubSub qui semble assez bien conçue. Le service peut être trouvé ici .
Aussi un schéma de leur service:
la source
En fait, utiliser émettre et diffuser est inefficace car l'événement bouillonne de haut en bas dans la hiérarchie de la portée, ce qui peut facilement se dégrader en réduction des performances pour une application complexe.
Je suggère d'utiliser un service. Voici comment je l'ai récemment implémenté dans l'un de mes projets - https://gist.github.com/3384419 .
Idée de base - enregistrer un pubsub / bus d'événements en tant que service. Injectez ensuite cet Eventbus partout où vous devez vous abonner ou publier des événements / sujets.
la source
$rootScope.$emit()
seules des bulles montent. Cependant, comme il n'y a pas de portée au-dessus,$rootScope
il n'y a rien à craindre. Donc, si vous utilisez juste$rootScope.$emit()
et$rootScope.$on()
vous aurez un EventBus rapide à l'échelle du système.$rootScope.$on()
intérieur de votre contrôleur, vous devrez nettoyer la liaison d'événement, sinon ils résumeront car il en crée un nouveau chaque fois que le contrôleur est instancié et ils ne le font pas être automatiquement détruit pour vous puisque vous vous liez$rootScope
directement à.En utilisant les méthodes get et set dans un service, vous pouvez très facilement passer des messages entre les contrôleurs.
en HTML HTML, vous pouvez vérifier comme ça
la source
En ce qui concerne le code d'origine - il semble que vous souhaitiez partager des données entre les étendues. Pour partager des données ou un état entre $ scope, les documents suggèrent d'utiliser un service:
Ref: lien Angular Docs ici
la source
J'ai en fait commencé à utiliser Postal.js comme bus de messages entre les contrôleurs.
Il présente de nombreux avantages en tant que bus de messages, comme les liaisons de style AMQP, la façon dont la poste peut intégrer des iFrames et des sockets Web, et bien d'autres choses.
J'ai utilisé un décorateur pour installer Postal sur
$scope.$bus
...Voici un lien vers un article de blog sur le sujet ...
http://jonathancreamer.com/an-angular-event-bus-with-postal-js/
la source
C'est ainsi que je le fais avec Factory / Services et l' injection de dépendance simple (DI) .
la source
J'ai aimé la façon dont
$rootscope.emit
était utilisé pour réaliser l'intercommunication. Je propose la solution propre et performante sans polluer l'espace global.la source
Voici le moyen rapide et sale.
Voici un exemple de fonction à ajouter dans l'un des contrôleurs frères:
et bien sûr voici votre HTML:
la source
$rootScope
?Démarrage d'angular 1.5 et de son développement basé sur les composants. La manière recommandée pour les composants d'interagir est d'utiliser la propriété 'require' et les liaisons de propriété (entrée / sortie).
Un composant nécessiterait un autre composant (par exemple le composant racine) et obtiendrait une référence à son contrôleur:
Vous pouvez ensuite utiliser les méthodes du composant racine dans votre composant enfant:
Il s'agit de la fonction de contrôleur de composant racine:
Voici un aperçu architectural complet: Communications de composants
la source
Vous pouvez accéder à cette fonction bonjour n'importe où dans le module
Contrôleur un
deuxième contrôleur
Plus d'infos ici
la source
Je vais créer un service et utiliser la notification.
Comme à tout moment le service de notification est singleton, il devrait être en mesure de fournir des données persistantes à travers.
J'espère que cela t'aides
la source
Vous pouvez utiliser le
$rootScope
service intégré AngularJS et injecter ce service dans vos deux contrôleurs. Vous pouvez ensuite écouter les événements déclenchés sur l'objet $ rootScope.$ rootScope fournit deux répartiteurs d'événements appelés
$emit and $broadcast
qui sont responsables de la répartition des événements (peuvent être des événements personnalisés) et utilisent la$rootScope.$on
fonction pour ajouter un écouteur d'événements.la source
Vous devez utiliser le Service, car l'
$rootscope
accès à partir de toute l'application, et cela augmente la charge, ou vous pouvez utiliser les rootparams si vos données ne sont pas plus.la source
la source
Vous pouvez le faire en utilisant des événements angulaires qui sont $ emit et $ broadcast. Selon nos connaissances, c'est le meilleur moyen, efficace et efficient.
D'abord, nous appelons une fonction d'un contrôleur.
Vous pouvez également utiliser $ rootScope à la place de $ scope. Utilisez votre contrôleur en conséquence.
la source