Qual é a maneira correta de se comunicar entre controladores?
Atualmente, estou usando um fudge horrível envolvendo 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);
}
}
Respostas:
Editar : o problema abordado nesta resposta foi resolvido na versão 1.2.7 do angular.js .
$broadcast
agora evita borbulhar em escopos não registrados e roda tão rápido quanto $ emitem.Então agora você pode:
$broadcast
partir do$rootScope
$on
do local$scope
que precisa saber sobre o eventoResposta original abaixo
Eu recomendo não usar
$rootScope.$broadcast
+,$scope.$on
mas sim$rootScope.$emit
+$rootScope.$on
. O primeiro pode causar sérios problemas de desempenho, conforme levantado pelo @numan. Isso ocorre porque o evento passará por todos os escopos.No entanto, o último (usando
$rootScope.$emit
+$rootScope.$on
) não sofre com isso e pode, portanto, ser usado como um canal de comunicação rápido!A partir da documentação angular de
$emit
:Como não há escopo acima
$rootScope
, não há bolhas acontecendo. É totalmente seguro usar$rootScope.$emit()
/$rootScope.$on()
como um EventBus.No entanto, há um problema ao usá-lo nos Controladores. Se você se vincular diretamente a
$rootScope.$on()
partir de dentro de um controlador, precisará limpar a ligação quando seu local$scope
for destruído. Isso ocorre porque os controladores (em contraste com os serviços) podem ser instanciados várias vezes ao longo da vida útil de um aplicativo, o que resultaria em ligações que acabariam criando eventualmente vazamentos de memória em todo o lugar :)Para cancelar o registro, basta ouvir em seu
$scope
's$destroy
evento e, em seguida, chamar a função que foi devolvido pelo$rootScope.$on
.Eu diria que isso não é realmente uma coisa específica angular, pois também se aplica a outras implementações do EventBus, que você precisa limpar os recursos.
No entanto, você pode facilitar sua vida para esses casos. Por exemplo, você pode usar o patch do macaco
$rootScope
e atribuir um$onRootScope
que assine os eventos emitidos no$rootScope
mas também limpe diretamente o manipulador quando o local$scope
for destruído.A maneira mais limpa de fazer o patch do macaco
$rootScope
para fornecer esse$onRootScope
método seria através de um decorador (um bloco de execução provavelmente também funcionará bem, mas pssst, não conte a ninguém)Para garantir que a
$onRootScope
propriedade não apareça inesperada ao enumerar$scope
, usamosObject.defineProperty()
e configuramosenumerable
comofalse
. Lembre-se de que você pode precisar de um calço ES5.Com este método, o código do controlador acima pode ser simplificado para:
Portanto, como resultado final de tudo isso, recomendo que você use
$rootScope.$emit
+$scope.$onRootScope
.Aliás, estou tentando convencer a equipe angular a resolver o problema dentro do núcleo angular. Há uma discussão em andamento aqui: https://github.com/angular/angular.js/issues/4574
Aqui está um jsperf que mostra o quanto de um impacto de desempenho
$broadcast
traz para a mesa em um cenário decente com apenas 100$scope
's.http://jsperf.com/rootscope-emit-vs-rootscope-broadcast
fonte
A resposta principal aqui foi uma solução alternativa para um problema angular que não existe mais (pelo menos nas versões> 1.2.16 e "provavelmente anterior") como o @zumalifeguard mencionou. Mas fiquei lendo todas essas respostas sem uma solução real.
Parece-me que a resposta agora deve ser
$broadcast
partir do$rootScope
$on
do local$scope
que precisa saber sobre o eventoEntão para publicar
E se inscrever
Plunkers
Controller As
sintaxeSe você registrar o ouvinte no local
$scope
, ele será destruído automaticamente por$destroy
si só quando o controlador associado é removido.fonte
controllerAs
sintaxe? Consegui usar$rootScope
o assinante para ouvir o evento, mas fiquei curioso para saber se havia um padrão diferente.$scope
explicitamente. John Papa escreve que os eventos são uma "exceção" à regra usual de manter$scope
"fora" de seus controladores (eu uso aspas porque, como ele mencionaController As
ainda o faz$scope
, está logo abaixo do capô).controller as
alternativa de sintaxe conforme solicitado. Espero que seja isso que você quis dizer.Usando $ rootScope. $ Broadcast e $ scope. $ On para uma comunicação PubSub.
Além disso, consulte este post: AngularJS - Comunicação entre controladores
fonte
$rootScope
e$watch
. Não tenho certeza se há alguma melhoria.Como defineProperty tem um problema de compatibilidade do navegador, acho que podemos pensar em usar um serviço.
e use-o no controlador como este:
controlador 1
controlador 2
fonte
O GridLinked publicou uma solução PubSub que parece ter sido projetada muito bem. O serviço pode ser encontrado aqui .
Também um diagrama de seu serviço:
fonte
Na verdade, o uso de emissão e transmissão é ineficiente porque o evento borbulha para cima e para baixo na hierarquia do escopo, o que pode facilmente se degradar em agrupamento de desempenho para um aplicativo complexo.
Eu sugeriria usar um serviço. Aqui está como eu o implementei recentemente em um dos meus projetos - https://gist.github.com/3384419 .
Ideia básica - registre um pubsub / evento como um serviço. Em seguida, injete o eventbus sempre que precisar para assinar ou publicar eventos / tópicos.
fonte
$rootScope.$emit()
apenas borbulha para cima. No entanto, como não há escopo acima do,$rootScope
não há nada a temer. Portanto, se você estiver apenas usando$rootScope.$emit()
e$rootScope.$on()
terá um EventBus rápido em todo o sistema.$rootScope.$on()
dentro do seu controlador, precisará limpar a ligação do evento, caso contrário eles serão resumidos, pois criará um novo cada vez que o controlador for instanciado e eles não é destruído automaticamente para você, pois você está vinculando$rootScope
diretamente.Usando métodos get e set em um serviço, você pode transmitir mensagens entre controladores com muita facilidade.
em HTML HTML, você pode verificar assim
fonte
Em relação ao código original - parece que você deseja compartilhar dados entre escopos. Para compartilhar Dados ou Estado entre o escopo $, os documentos sugerem o uso de um serviço:
Ref: Link para Documento Angular aqui
fonte
Na verdade, comecei a usar o Postal.js como um barramento de mensagens entre controladores.
Existem muitos benefícios para ele, como um barramento de mensagens, como ligações no estilo AMQP, a maneira como o postal pode integrar w / iFrames e soquetes da web e muito mais.
Eu usei um decorador para configurar o Postal
$scope.$bus
...Aqui está um link para uma postagem de blog sobre o tópico ...
http://jonathancreamer.com/an-angular-event-bus-with-postal-js/
fonte
É assim que eu faço com Fábrica / Serviços e injeção simples de dependência (DI) .
fonte
Gostei da maneira como
$rootscope.emit
foi usado para alcançar a intercomunicação. Sugiro a solução limpa e com desempenho eficiente, sem poluir o espaço global.fonte
Aqui está o caminho rápido e sujo.
Aqui está um exemplo de função para adicionar em qualquer um dos controladores irmãos:
e, claro, aqui está o seu HTML:
fonte
$rootScope
?Iniciando o angular 1.5 e seu foco no desenvolvimento baseado em componentes. A maneira recomendada para os componentes interagirem é através do uso da propriedade 'require' e através de ligações de propriedade (entrada / saída).
Um componente exigiria outro componente (por exemplo, o componente raiz) e obteria uma referência ao seu controlador:
Você pode usar os métodos do componente raiz no componente filho:
Esta é a função do controlador de componente raiz:
Aqui está uma visão geral da arquitetura completa: Comunicações de componentes
fonte
Você pode acessar esta função hello em qualquer lugar do módulo
Controlador um
segundo controlador
Mais informações aqui
fonte
Vou criar um serviço e usar a notificação.
Como a qualquer momento o Serviço de Notificação é único, ele deve poder fornecer dados persistentes.
Espero que isto ajude
fonte
Você pode usar o serviço embutido do AngularJS
$rootScope
e injetar esse serviço nos dois controladores. Você pode ouvir eventos disparados no objeto $ rootScope.O $ rootScope fornece dois expedidores de eventos chamados
$emit and $broadcast
responsáveis pelo envio de eventos (podem ser eventos personalizados) e usam a$rootScope.$on
função para adicionar ouvintes de eventos.fonte
Você deve usar o Serviço, porque
$rootscope
é o acesso de todo o Aplicativo, e aumenta a carga, ou você pode usar os parâmetros raiz se seus dados não forem maiores.fonte
fonte
Você pode fazer isso usando eventos angulares que são $ emitem e $ transmitem. De acordo com nosso conhecimento, esta é a melhor maneira, eficiente e eficaz.
Primeiro chamamos uma função de um controlador.
Você também pode usar $ rootScope no lugar de $ scope. Use seu controlador de acordo.
fonte