422 votes

Comment regarder les variables de service ?

J'ai un service à la, dire:

factory('aService', ['$rootScope', '$resource', function ($rootScope, $resource) {
  var service = {
    foo: []
  };

  return service;
}]);

Et je voudrais utiliser foo de contrôle une liste est au format HTML:

<div ng-controller="FooCtrl">
  <div ng-repeat="item in foo">{{ item }}</div>
</div>

Pour que le contrôleur de détecter lorsqu' aService.foo est mis à jour, j'ai bricolé ce modèle où je ajouter de service pour le contrôleur $scope , puis utiliser $scope.$watch():

function FooCtrl($scope, aService) {                                                                                                                              
  $scope.aService = aService;
  $scope.foo = aService.foo;

  $scope.$watch('aService.foo', function (newVal, oldVal, scope) {
    if(newVal) { 
      scope.foo = newVal;
    }
  });
}

Cela se sent à longue main, et j'ai été le répéter dans chaque contrôleur qui utilise le service de variables. Est-il un meilleur moyen d'obtenir regarder de variables partagées?

280voto

dtheodor Points 1383

Vous pouvez toujours utiliser le bon vieux modèle observateur si vous voulez éviter la tyrannie et les frais généraux de `` .

Dans le service :

Et dans le contrôleur :

232voto

Matt Pileggi Points 2603

Dans un tel scénario, où plusieurs/unkown objets pourraient être intéressés par les changements, utilisez $rootScope.$broadcast de l'élément en cours de modification.

Plutôt que de créer votre propre registre des auditeurs (qui doivent être nettoyés sur divers $détruit), vous devez être en mesure d' $broadcast à partir du service en question.

Vous devez toujours le code de l' $on des gestionnaires à chaque auditeur, mais le motif est découplée de multiples appels à l' $digest et évite donc le risque de longue watchers.

De cette façon, aussi, les auditeurs peuvent aller et venir de la DOM et/ou différent de l'enfant étendues sans le service de changement de comportement.

** mise à jour: exemples **

Émissions ferait le plus de sens dans l'onglet "global" des services qui pourraient avoir un impact d'innombrables autres choses dans votre application. Un bon exemple est celui d'un Utilisateur de service où il y a un certain nombre d'événements qui pourraient avoir lieu tel que la connexion, la déconnexion, la mise à jour, ralenti, etc. Je crois que c'est où les émissions ont le plus de sens parce que tout peut écouter un événement, sans même l'injection du service, et il n'a pas besoin d'évaluer toutes les expressions ou mettre en cache les résultats d'inspecter pour des changements. Il vient de feux et oublie (donc, assurez-sûr que c'est un feu-et-oublier de notification, et non pas quelque chose qui nécessite une action)

.factory('UserService', [ '$rootScope', function($rootScope) {
   var service = <whatever you do for the object>

   service.save = function(data) {
     .. validate data and update model ..
     // notify listeners and provide the data that changed [optional]
     $rootScope.$broadcast('user:updated',data);
   }

   // alternatively, create a callback function and $broadcast from there if making an ajax call

   return service;
}]);

Le service ci-dessus serait de diffuser un message à tous les portée lors de la save() la fonction s'est terminée et que les données soient valides. Sinon, si c'est une de dollars de ressources ou une soumission ajax, déplacer la diffusion d'appels à la fonction de rappel de sorte qu'il se déclenche lorsque le serveur a répondu. Émissions en fonction de ce modèle particulièrement bien parce que chaque auditeur attend simplement la manifestation sans la nécessité de contrôler la portée sur chaque $digest. L'auditeur pourrait ressembler à:

.controller('UserCtrl', [ 'UserService', '$scope', function(UserService, $scope) {

  var user = UserService.getUser();

  // if you don't want to expose the actual object in your scope you could expose just the values, or derive a value for your purposes
   $scope.name = user.firstname + ' ' +user.lastname;

   $scope.$on('user:updated', function(event,data) {
     // you could inspect the data to see if what you care about changed, or just update your own scope
     $scope.name = user.firstname + ' ' + user.lastname;
   });

   // different event names let you group your code and logic by what happened
   $scope.$on('user:logout', function(event,data) {
     .. do something differently entirely ..
   });

 }]);

L'un des avantages de ceci est l'élimination de plusieurs montres. Si vous étiez en combinant les champs ou en découlant, des valeurs comme l'exemple ci-dessus, vous devez regarder à la fois les propriétés firstname et lastname. Regarder le getUser() la fonction ne fonctionne que si l'utilisateur de l'objet a été remplacé sur les mises à jour, il ne serait pas le feu si l'utilisateur de l'objet seulement de ses propriétés de mise à jour. Dans ce cas, vous auriez à faire une profonde regarder et ce qui est de plus en plus intensive.

$broadcast envoie le message de la portée, il est appelé à descendre dans n'importe quel enfant étendues. Donc l'appeler à partir de $rootScope le feu sur chaque portée. Si vous étiez à $diffusé à partir de votre contrôleur du champ d'application, par exemple, il serait de feu que dans les étendues qui héritent de votre contrôleur de portée. $émettent va dans le sens inverse et se comporte de façon similaire à un DOM événement en ce qu'il les bulles du champ d'application de la chaîne.

Gardez à l'esprit qu'il existe des scénarios où $de diffusion fait beaucoup de sens, et il existe des scénarios où $watch est une meilleure option, surtout si dans un isolat portée avec une très montre spécifique de l'expression.

49voto

Krym Points 176

Je suis approche similaire comme @dtheodot mais en utilisant la promesse angulaire au lieu de passer des rappels

Ensuite partout où il suffit d’utiliser méthode pour mettre à jour sur le service. Dans votre contrôleur, vous pouvez utiliser comme :

Deux premiers arguments de `` sont des rappels de succès et d’erreurs, un troisième est notifier le rappel.

Référence pour $q.

28voto

ganaraj Points 14228

Aussi loin que je peux dire, vous n'avez pas à faire quelque chose d'aussi élaboré que ça. Vous avez déjà attribué foo de ce service à votre portée et depuis foo est un tableau ( et à son tour un objet, qu'il est affecté par la référence! ). Donc, tout ce que vous devez faire est de quelque chose comme ceci :

function FooCtrl($scope, aService) {                                                                                                                              
  $scope.foo = aService.foo;

 }

Si certains, d'autres variables dans cette même touche Ctrl est personne à charge sur foo change alors oui, vous avez besoin d'une montre pour observer foo et apporter des modifications à cette variable. Mais tant que c'est une simple référence à regarder est inutile. Espérons que cette aide.

13voto

rxgx Points 2468

Voici comment j’ai implémenté un service dans mes contrôleurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X