10

Finora ho visto molte soluzioni del problema. Il più semplice è, naturalmente, $emit un evento in $rootScope come un bus di eventi, ad es. (https://github.com/btilford/anti-patterns/blob/master/angular/Angular.md)comunicazione globale nel modulo angolare: bus di eventi o modello di mediatore/servizio

angular.module('myModule').directive('directiveA', function($rootScope) { 
    return { 
    link : function($scope, $element) { 
     $element.on('click', function(event) { 
     $rootScope.$emit('directiveA:clicked', event); 
     }); 
    } 
    } 
}); 
angular.module('myModule').directive('directiveB', function() { 
    return { 
    link : function($scope, $element) { 
     $rootScope.on('directiveA:clicked', function(event) { 
     console.log('received click event from directiveA'); 
     }); 
    } 
    } 
}); 

e un altro è dichiarare un servizio con una funzionalità mediatore o PubSub/un ambito chiuso ad esempio (. Communicating between a Multiple Controllers and a directive)

module.factory('MessageService', 
    function() { 
    var MessageService = {}; 

    var listeners = {}; 
    var count = 0; 
    MessageService.registerListener = function(listener) { 
     listeners[count] = listener; 
     count++; 

     return (function(currentCount) { 
     return function() { 
      delete listeners[currentCount]; 
     } 
     })(count); 
    } 

    MessageService.broadcastMessage = function(message) { 
     var keys = Object.keys(listeners); 

     for (var i = 0; i < keys.length; i++) { 
     listeners[keys[i]](message); 
     } 
    } 

    return MessageService; 
    } 
); 

La domanda sono:

  • c'è punto di utilizzare il secondo in un'applicazione angolare?
  • e quali sono i pro e i contro di ciascuno di questi in confronto tra loro?
+0

la tua domanda sembra interessante, ma per favore aggiungi qualche dettaglio del tuo modulo per evitare downvotes e chiudi prematuramente la tua domanda – InferOn

+0

che tipo di comunicazione? –

+0

es. Semplice scambio di modello o funzione di sparo in un altro ambito/direttiva ecc. –

risposta

14

Creare la propria implementazione di emettitore evento è controproducente quando si scrive un'applicazione AngularJS. Angular fornisce già tutti gli strumenti necessari per la comunicazione basata sugli eventi.

  • Utilizzando $emit su $rootScope funziona bene per la comunicazione inter-servizio globale e non ha davvero alcun svantaggi.
  • L'utilizzo di $broadcast su un ambito naturale (uno associato a una parte del DOM) fornisce una comunicazione con scope tra i componenti di visualizzazione (direttive, controller).
  • L'utilizzo di $broadcast su $rootScope riunisce i due punti precedenti (fornisce una piattaforma di comunicazione completamente globale). Questa è la soluzione utilizzata fondamentalmente da qualsiasi libreria basata su AngularJS.

e

  • Se siete preoccupati per le prestazioni in opzione precedente e si vuole veramente il tuo emettitore evento separato, è possibile creare facilmente uno per la creazione di un ambito isolato ($rootScope.$new(true)) e l'utilizzo di $broadcast su di essa. (Si può quindi avvolgerlo in un servizio e iniettare ovunque si desidera.)

L'ultima opzione consente di creare un evento a tutti gli effetti emettitore integrato nel angolare (l'attuazione prevista nella tua domanda avrebbe almeno bisogno di avvolgere tutto ascoltatore chiama in $apply() per integrarsi correttamente) che può essere utilizzato anche per l'osservazione dei cambiamenti di dati, se questo si adatta a un caso d'uso particolare.

Tuttavia, a meno che la tua applicazione non sia davvero enorme, o sei davvero paranoico riguardo alle collisioni dei nomi degli eventi, le prime tre opzioni dovrebbero essere sufficienti.


Non voglio entrare nei dettagli su altri mezzi di comunicazione tra i componenti. In generale, quando la situazione richiede la condivisione dei dati utilizzando l'ambito, l'interazione diretta dei controller o la comunicazione attraverso gli attributi del DOM, è necessario saperlo.

+0

Buon post su Event Bus con $ rootscope: http: //www.johanilsson .com/2014/04/angularjs-EventBus / – pdorgambide

10

Direi che la trasmissione è un modo angolare per ottenere ciò.

Tuttavia, il tuo mediatore può funzionare, se si passa la funzione di direttiva interna, nell'esempio ho utilizzato il metodo sull'ambito, ma può essere eseguito anche con il metodo del controller.

Ho usato esattamente la stessa fabbrica che pubblichi.

angular.module("sharedService", []) 
.factory('MessageService', 
    function() { 
    var MessageService = {}; 

    var listeners = {}; 
    var count = 0; 
    MessageService.registerListener = function(listener) { 
     listeners[count] = listener; 
     count++; 

     return (function(currentCount) { 
     return function() { 
      delete listeners[currentCount]; 
     }; 
     })(count); 
    }; 

    MessageService.broadcastMessage = function(message) { 
     var keys = Object.keys(listeners); 

     for (var i = 0; i < keys.length; i++) { 
     listeners[keys[i]](message); 
     } 
    }; 

    return MessageService; 
    } 
) 

.directive("directiveA", function(MessageService) { 
    return { 
    link:function(scope) { 
     scope.click = function() { 
     MessageService.broadcastMessage("broadcasted message"); 
     }; 
    }, 
    template: '<button ng-click="click()">Click</button>' 
    }; 
}) 
.directive("directiveB", function(MessageService) { 
    return { 
    link:function(scope) {   
     scope.callback = function(message) { 
     console.log(message); 
     }; 

     MessageService.registerListener(scope.callback); 
    } 
    }; 
}); 

completa esempio: http://jsbin.com/mobifuketi/1/edit?html,js,console,output

solo per essere completa, vorrei aggiungere, che angolare fornisce anche più posibilities come possono comunicare direttive.

Richiede atribute

Se le direttive sono collegati in gerarchia, quindi è possibile utilizzare l'attributo richiede che consentono di accedere ad altri controller di direttive. Questa è di solito la migliore soluzione per molti casi.

.directive("directiveA", function() { 
    return { 
    require: "^directiveB", 

    link: function(scope, element, attrs, directiveCtrl) { 

     scope.click = function() { 
     directiveCtrl.call(); 
     }; 
    }, 
    template: '<button ng-click="click()">Click</button>' 
    }; 
}) 
.directive("directiveB", function() { 
    return { 
    controller :function() { 
     this.call = function() { 

     console.log("method has been called"); 
     }; 
    } 
    }; 
}); 

esempio completa: http://jsbin.com/turoxikute/1/edit?html,js,console,output

Utilizzando $ guardare

Se i deppends funzionalità sui dati e non su azione, si Cen usano $ guardare e reagiscono ai cambiamenti del dato modello o modello memorizzato nel servizio condiviso, non è come ascoltatore, il suo controllo base del cambiamento. Ho chiamato il metodo changeState() e registro "stato modificato" per chiunque lo veda chiaro.

angular.module("sharedService", []) 
.service("MediatorService", function() { 
    this.state = true; 

    this.changeState = function() { 
    this.state = !this.state; 
    }; 
}) 

.directive("directiveA", function(MediatorService) { 
    return { 
    link:function(scope) { 

     scope.click = function() { 
     MediatorService.changeState(); 
     }; 
    }, 
    template: '<button ng-click="click()">Click</button>' 
    }; 
}) 

.directive("directiveB", function(MediatorService) { 
    return { 
    link:function(scope) { 
     scope.mediator = MediatorService; 
     scope.$watch("mediator.state", function(oldValue, newValue) { 
     if (oldValue == newValue) { 
      return; 
     } 

     console.log("state changed"); 
     }); 
    } 
    }; 
}); 

esempio completa: http://jsbin.com/darefijeto/1/edit?html,js,console,output

3

Mi piace un bus eventi.

Angular fornisce $ emit su $ rootScope ma non penso che dovrebbe vincolare la decisione di usarlo per flussi basati su eventi se sono complessi o prevedibilmente complessi. Angular ha molte funzionalità e mentre la maggior parte sono grandiose, anche gli autori ammettono che sono principalmente pensate per complimentarmi con i buoni principi di ingegneria del software, non per sostituirli.

Mi piace questo post sull'utilizzo di postal.js: An angular.js event bus with postal.js. I due principali vantaggi sono i canali e le buste, che renderanno la logica basata su eventi più esplicita, comprensibile e flessibile.

Trovo che gli approcci basati sul servizio siano soggetti a errori se lo stato non viene gestito in modo stretto, il che è difficile con chiamate asincrone e iniezioni, in cui non si può essere certi di come un servizio sarà multiprogettato in futuro.

Problemi correlati