2016-05-05 20 views
10

Voglio creare un meccanismo di pubblicazione/sottoscrizione con sistema di eventi angolare.Comunicazione evento Angularjs tra direttive con pubblicazione/sottoscrizione

angular.module("app",[]); 

angular.module("app").directive("first", function($rootScope){ 
     return { 
      template: "First Directive", 
      link:function(scope,element,attribute){ 
       $rootScope.$broadcast("OnFirstDirectiveCreated", { 
       "message": "I'm first directive" 
      }); 
     } 
    } 
}) 

angular.module("app").directive("second", function($rootScope){ 
     return { 
      template: "Second Directive", 
      link:function(scope,element,attribute){ 
      var handler = $rootScope.$on("OnFirstDirectiveCreated", 
       function (event, args) { 
        console.log("First Directive Message: " + args.message); 
      }); 
     } 
    } 
}) 

se ho impostato documento HTML come questo, nessun messaggio appaiono in console:

<div ng-app="app"> 
    <first></first> 
    <second></second> 
</div> 

Se cambio ordine prima e la seconda, il messaggio wirite su console.

<div ng-app="app"> 
    <second></second> 
    <first></first> 
</div> 

Ma ho bisogno della prima direttiva o direttiva interna.

<div ng-app="app"> 
    <first></first> 
    <second></second> 
</div> 

<div ng-app="app"> 
    <first> 
     <second></second> 
    </first> 
</div> 

Ho provato entrambi $rootScope.$broadcast e $rootScope.$emit ma non ha woeked.

Working DEMO

risposta

4

E 'assolutamente corretto comportamento angolare.

Nel primo esempio:

<first></first> 
<second></second> 

angolare crea una direttiva per first tag e invia immediatamente evento, ma la seconda direttiva non è ancora creata.

Nel secondo esempio:

<first></first> 
<second></second> 

Qui in primo luogo sottoscrive un evento, e dopo che la direttiva first invia un messaggio. Per questo motivo, la direttiva second accetta un evento.

Terzo esempio:

<first> 
    <second></second> 
</first> 

questo caso, così come il primo esempio non dovrà lavorare.

Soluzione: Una delle soluzioni è impostare il timeout nella prima direttiva per non inviare l'evento immediatamente dopo la creazione. Se il secondo parametro di $timeout, delay non viene fornito, il comportamento predefinito è quello di eseguire la funzione dopo che il DOM ha completato il rendering:

angular.module("app").directive("first", function($rootScope, $timeout) { 
    return { 
    template: "First Directive", 
    link: function(scope,element,attribute) { 
     $timeout(function() { 
     $rootScope.$broadcast("OnFirstDirectiveCreated", { 
      "message": "I'm first directive" 
     }) 
     }); 
    } 
    } 
}); 

Demo

+0

$ timeout 0 secondi è un po 'confuso me. Se la mia seconda direttiva carica qualche secondo, potrebbe essere un problema? Non possiamo sapere il tempo di caricamento delle altre direttive. – barteloma

+0

Ho aggiornato una risposta, se userai '$ timeout' senza parametro' delay', la funzione verrà eseguita dopo che il DOM ha completato il rendering. – alexmac

1

Questo accade perché quando viene eseguita la trasmissione della prima direttiva, la seconda direttiva non è pronta e quindi il segnale viene perso e la comunicazione non avviene. Un modo per risolverlo è inviare più volte il segnale utilizzando la funzione $ interval e interrompere la trasmissione solo quando la seconda direttiva è pronta. Ovviamente la seconda direttiva deve tornare indietro quando riceve i dati dal primo. La seconda soluzione, per la quale vorrei andare, è che la seconda direttiva notifichi quando è pronta per la prima direttiva trasmettendo con $ rootScope in un modo simile a quello della prima direttiva.

angular.module("app").directive("second", function($rootScope){ 
    return { 
     template: "Second Directive", 
     link:function(scope,element,attribute){ 
     var handler = $rootScope.$on("secondDirective", 
      function (event, args) { 
       console.log("First Directive Data: " + args); 
     }); 

     $rootScope.$broadcast("OnChildDirectiveCreated", { 
      "message": "I'm second directive", 
      "id":  "secondDirective" 
     }); 
     } 
    } 
}) 

e la prima direttiva:

angular.module("app").directive("first", function($rootScope){ 
    return { 
     template: "First Directive", 
     link:function(scope,element,attribute){ 
      $rootScope.$on("OnChildDirectiveCreated", function(event, args) { 
       $rootScope.$broadcast(args.id, someData); 
      }); 
     } 
    } 
}) 

Dal momento che si sta utilizzando una struttura padre-figlio, è sempre garantito che la prima direttiva sarà pronta quando le direttive bambino sono pronti. Usando questa soluzione potresti usare molte direttive bambino. Spero che questo ti aiuti!

Problemi correlati