2013-04-24 17 views
53

Ho visto gente che fa questo da ovunque nel loro codice:AngularJS: evento di trasmissione dalla direttiva

$rootScope.$broadcast('someEvent', someParameter); 

e poi in qualche controllore:

$rootScope.$on('someEvent', function(event, e){ /* implementation here */ }); 

Ora, mi piacerebbe broacast un evento da una direttiva. È buona pratica trasmetterlo a livello rootScope? Mi piacerebbe gestire questo evento in un controller. Posso usare $ scope, o devo ancora ascoltare su $ rootScope?

+0

si fa a hanno isolato la portata della direttiva di usare Ambito principale del controllore –

risposta

76

Nel mio caso, voglio solo trasmettere un anche da una direttiva al controller della vista, in cui utilizzo la direttiva. Ha ancora senso usare la trasmissione allora?

avrei la direttiva chiamare un metodo sul controller, che è specificato nel codice HTML in cui viene utilizzata la direttiva:

Per una direttiva che utilizza un ambito isolato:

<div my-dir ctrl-fn="someCtrlFn(arg1)"></div> 

app.directive('myDir', function() { 
    return { 
    scope: { ctrlFn: '&' }, 
    link: function(scope, element, attrs) { 
     ... 
     scope.ctrlFn({arg1: someValue}); 
    } 

Per una direttiva che non utilizza un ambito isolato:

<div my-dir ctrl-fn="someCtrlFn(arg1)"></div> 

app.directive('myDir', function($parse) { 
    return { 
    scope: true, // or no new scope -- i.e., remove this line 
    link: function(scope, element, attrs) { 
     var invoker = $parse(attrs.ctrlFn); 
     ... 
     invoker(scope, {arg1: someValue}); 
    } 
+0

in realtà, lo sto già facendo. Ma volevo usare la trasmissione di eventi come pensavo sarebbe stata una pratica migliore. Non è in questo caso? $ emettono e $ su suono buono :) – Sam

+0

@ Sam, non so quale sia la pratica migliore. Un evento si traduce in un maggiore accoppiamento tra la direttiva e il controller in quanto il controller deve ascoltare un evento specifico emesso dalla direttiva. Preferisco usare un metodo perché è più esplicito/dichiarativo che la direttiva comunicherà con il controller e posso dichiarare nel mio HTML come ciò accade. –

+0

ok, grazie per il vostro consiglio! – Sam

13

Di solito è una buona idea non utilizzare $ rootScope poiché è globale e non si dovrebbe inquinare a meno che non si sappia davvero cosa si sta facendo. Ti consiglio di leggere this article about communication between services, directives and controllers.

+1

in base all'articolo: "Ogni volta che si verifica un evento nella propria applicazione che riguarda tutti i controller e le direttive". Nel mio caso, voglio solo trasmettere un messaggio anche da una direttiva al controller della vista, in cui utilizzo la direttiva.Ha ancora senso usare la trasmissione allora? – Sam

+1

no non si dovrebbe trasmettere, la trasmissione ha lo scopo di inviare eventi dall'ambito padre a tutti gli ambiti figlio e si sta facendo diversamente da –

+7

Sì, se si desidera ascoltare eventi da un controller genitore si dovrebbe fare '$ scope. $ emit' nella direttiva e '$ scope. $ on' nel controllore genitore – joakimbl

0

Ecco un esempio TypeScript di come chiamare indietro un metodo sul controller da una direttiva incorporata. La cosa più importante da notare è che il nome del parametro della direttiva per la callback utilizza uno & quando definito, e quando si chiama quel callback non si devono usare parametri posizionali ma si usa invece un oggetto con proprietà che hanno i nomi dei parametri nella destinazione.

Registrati direttiva quando si crea il modulo app:

module MyApp { 
    var app: angular.IModule = angular.module("MyApp"); 
    MyApp.Directives.FileUploader.register(app); 
} 

Il codice di registrazione è il seguente:

Il controllore della direttiva sarebbe simile a questa

module MyApp.Directives.FileUploader { 
    export class Controller { 
     public files: string[] = ["One", "Two", "Three"]; 
     //The callback specified in the view that created this directive instance 
     public onFileItemClicked: (fileItem) => void; 

     // This is the controller method called from its HTML's ng-click 
     public fileItemClicked(fileItem) { 
      //IMPORTANT: Don't use comma separated parameters, 
      //instead use an object with property names to act as named parameters 
      this.onFileItemClicked({ 
       fileItem: fileItem 
      }); 
     } 
    } 
} 

Il l'HTML della direttiva sarebbe simile a questo

<ul> 
    <li ng-repeat="item in controller.files" ng-click="controller.fileItemClicked (item)"> 
    {{ item }} 
    </li> 
</ul> 

La vista principale avrà un'istanza della direttiva in questo modo

<body ng-app="MyApp" ng-controller="MainController as controller"> 
    <file-uploader on-file-item-clicked="controller.fileItemClicked(fileItem)"/> 
</body> 

Ora tutto ciò che serve sul tuo MainController è un metodo

public fileItemClicked(fileItem) { 
    alert("Clicked " + fileItem); 
} 
+0

Ci sono così tanti tipi che non è necessario scrivere manualmente ... – Zen

+0

Gusto personale :) –

+1

Usato come modello per chiamare un metodo controller padre da una direttiva nidificata a 2 livelli di profondità. Molto obbligato. p.s. Penso che tu abbia un refuso nell'HTML della direttiva - dovrebbe essere controller.fileItemClicked not controller.onFileItemSelected. –

Problemi correlati