2013-02-12 6 views
19

Ho una direttiva che associa alcune funzioni allo scope locale con $scope.$on.

È possibile associare la stessa funzione a più eventi in una chiamata?

Idealmente mi piacerebbe essere in grado di fare qualcosa del genere:

app.directive('multipleSadness', function() { 
    return { 
     restrict: 'C', 
     link: function(scope, elem, attrs) { 
      scope.$on('event:auth-loginRequired event:auth-loginSuccessful', function() { 
       console.log('The Ferrari is to a Mini what AngularJS is to ... other JavaScript frameworks'); 
      }); 
     } 
    }; 
}); 

Ma questo non funziona. Lo stesso esempio con la stringa del nome evento separata da virgole sostituita con ['event:auth-loginRequired', 'event:auth-loginConfirmed'] non distrugge nessuno dei due.

quello che funziona è questo:

app.directive('multipleSadness', function() { 
    return { 
     restrict: 'C', 
     link: function(scope, elem, attrs) { 

      scope.$on('event:auth-loginRequired', function() { 
       console.log('The Ferrari is to a Mini what AngularJS is to ... other JavaScript frameworks'); 
      }); 
      scope.$on('event:auth-loginConfirmed', function() { 
       console.log('The Ferrari is to a Mini what AngularJS is to ... other JavaScript frameworks'); 
      }); 
     } 
    }; 
}); 

Ma questo non è l'ideale.

È possibile associare più eventi alla stessa funzione in una volta sola?

risposta

11

Sì. Così:

app.directive('multipleSadness', function() { 
    return { 
     restrict: 'C', 
     link: function(scope, elem, attrs) { 

      function sameFunction(eventId) { 
       console.log('Event: ' + eventId + '. The Ferrari is to a Mini what AngularJS is to ... other JavaScript frameworks.'); 
      } 

      scope.$on('event:auth-loginRequired', function() {sameFunction('auth-loginRequired');}); 
      scope.$on('event:auth-loginConfirmed', function() {sameFunction('auth-loginConfirmed');}); 
     } 
    }; 
}); 

Ma solo perché è possibile, non significa che dovresti :). Se gli eventi continuano a propagarsi fino a un altro listener e vengono gestiti in modo diverso lì, allora forse c'è un caso per farlo. Se questo sarà l'unico ascoltatore di quanto dovresti semplicemente emettere (o trasmettere) lo stesso evento.

+0

Grazie per le informazioni aggiuntive sulla propagazione degli eventi e sugli ID degli eventi, sapendo questo capisco perché ciò che chiedo non è nativamente possibile. Gli eventi hanno ascoltatori diversi, tuttavia questo ascoltatore deve eseguire la stessa azione su più eventi. –

+0

Dopo l'esame ho refactored il mio codice per essere più * Angular *. Ci sono ancora due eventi, ma poiché significano cose diverse (nel refactoring), non c'è motivo di vincolarli entrambi alla stessa funzione. Grazie per i suggerimenti. –

+0

Nessun problema. Sono contento di poterti aiutare. – testing123

7

Non penso sia possibile, dal momento che l'evento potrebbe inviare dati al callback e se si ascoltano più eventi non si saprebbe quali dati provengono da quale evento.

avrei fatto qualcosa di simile:

function listener() { 
    console.log('event fired'); 
} 
scope.$on('event:auth-loginRequired', listener); 
scope.$on('event:auth-loginConfirmed', listener); 
13

AngularJS non supporta evento più vincolante, ma si può fare qualcosa di simile:

var handler = function() { ... } 
angular.forEach("event:auth-loginRequired event:auth-loginConfirmed".split(" "), function (event) { 
    scope.$on(event, handler); 
}); 
+1

C'è un motivo per cui si dovrebbe utilizzare "evento: auth-loginRequired evento: auth-loginConfirmed" .split ("") anziché solo ['evento: auth-loginRequired', 'event: auth-loginConfirmed']? –

+0

@ RyanO'Neill Nessun motivo speciale =) Sembra più pulito avere una singola stringa che avere ['', '', '', ...]. Anche l'esempio di OP era con una singola stringa separata da virgole. – bmleite

+2

Grazie. JavaScript è quello che è, volevo solo assicurarmi che non mi mancasse un momento di Wat che dovrei sapere. –

27

Le altre risposte (Anders Ekdahl) sono 100% corretto ... sceglierne uno di quelli ... MA ...

A parte ciò, si può sempre rotolare il proprio:

// a hack to extend the $rootScope 
app.run(function($rootScope) { 
    $rootScope.$onMany = function(events, fn) { 
     for(var i = 0; i < events.length; i++) { 
     this.$on(events[i], fn); 
     } 
    } 
}); 

app.directive('multipleSadness', function() { 
    return { 
     restrict: 'C', 
     link: function(scope, elem, attrs) { 
      scope.$onMany(['event:auth-loginRequired', 'event:auth-loginSuccessful'], function() { 
       console.log('The Ferrari is to a Mini what AngularJS is to ... other JavaScript frameworks'); 
      }); 
     } 
    }; 
}); 

Suppongo che se volessi davvero fare lo .split(','), ma questo è un dettaglio di implementazione.

+1

Dovresti inviarlo come PR Potrei usarlo. Forse prenderò solo il tuo credito. –

+1

Controllare la lunghezza di ogni iterazione è molto costoso; è meglio assegnare la lunghezza a una variabile –

+7

@ VerdiErelErgün "molto costosa"? Quante volte per ms ti esponi per essere colpito? È una chiamata una tantum per impostare alcuni binding. La micro-ottimizzazione non era proprio il punto qui ... Ma sì, si potrebbe 'for (var i = 0, len = events.length; i

1

piace anche con $ rootScope $ onMany (soluzione da @ Ben-Lesh) è possibile estendere $ sul metodo:.

var $onOrigin = $rootScope.$on; 

$rootScope.$on = function(names, listener) { 
    var self = this; 

    if (!angular.isArray(names)) { 
    names = [names]; 
    } 

    names.forEach(function(name) { 
    $onOrigin.call(self, name, listener); 
    }); 

}; 

preso da here.

+1

è necessario modificare '$ rootScope .__ proto __. $ On' (o' $ rootScope.constructor.prototype. $ On') se si desidera che gli ambiti figlio ereditino anche la funzione modificata. – cipak