web-dev-qa-db-fra.com

AngularJS, cette façon d'utiliser le service est-elle bonne?

j'ai ce HTML:

<p>Hello {{name}}</p>

et le contrôleur est:

function myCtrl(scope, service) {
    scope.name = service.getUsername(); // service.getUsername() return "World!"
}
myCtrl.$inject = ['$scope', 'originalService'];

Le service fonctionne bien, donc je ne colle pas le code ici ... Dans ce cas, le résultat est "Bonjour tout le monde!" J'ai changé le HTML de cette façon:

<p>Hello {{service.getUsername()}}</p>

Mais cela ne fonctionne pas.

J'ai changé de contrôleur:

function myCtrl(scope, service) {
    scope.ser = service;
}
myCtrl.$inject = ['$scope', 'originalService'];

puis le HTML

<p>Hello {{ser.getUsername();}}</p>

Cela fonctionne!

Ma question est donc:

Est-ce la seule façon d'utiliser les fonctions d'un service directement dans le HTML, ou il me manque quelque chose?

28
Bruno

Les modèles AngularJS ne peuvent appeler que des fonctions disponibles sur une étendue. Donc, quelle que soit l'approche que vous adoptez, vous devez avoir votre fonction sur une portée.

Si vous souhaitez que les fonctions de votre service soient directement invocables à partir d'un modèle, vous avez plusieurs options:

Celui que vous avez essayé - c'est-à-dire exposer l'ensemble du service sur une portée :

$scope.service = service;

puis dans un modèle:

<p>Hello {{service.getUsername();}}</p>

Il s'agit d'une ligne unique dans un contrôleur et rend toutes les méthodes de service disponibles sur une étendue et donc sur des modèles.

Exposez les méthodes une par une

pour avoir un contrôle précis sur ce qui est exposé:

$scope.getUsername = service.getUsername;

puis dans un modèle:

<p>Hello {{getUsername();}}</p>

Cela nécessite plus de méthodes d'exposition du travail mais vous donne un contrôle fin sur ce qui est exposé.

Exposez les méthodes de proxy :

$scope.getMyUsername = function() {
   //pre/post processing if needed 
   return service.getUsername();
};

Vous pouvez utiliser n'importe laquelle de ces méthodes ou les mélanger et les combiner, mais à la fin de la journée, une fonction doit se retrouver sur une étendue (soit directement soit via un autre objet exposé sur une étendue).

61
pkozlowski.opensource

Une autre façon de procéder:

Exposez le service sur $ rootScope :

$rootScope.service = service;

puis dans un modèle:

<p>Hello {{service.getUsername();}}</p>

Vous pouvez le faire sur app.run, et vous obtiendrez le service dans toutes les vues de votre application. Vous pouvez utiliser cette méthode pour les services d'authentification.

14

Une autre façon d'exposer votre service dans votre portée $ serait d'ajouter un pointeur de fonction à votre méthode de service/objet de données.

scope.serviceData = service.data;
// Or
scope.getServiceData = service.getData;

Dans votre vue, vous pouvez ensuite l'invoquer en utilisant des parenthèses.

<input ng-model="serviceData().key" />
// Or
<input ng-model="getServiceData().key" />
// Or
{{getServiceData().key}}

Personnellement, j'aime cette approche et je l'utilise actuellement afin de synchroniser plusieurs vues avec les mêmes données. Cela soulève certains problèmes, comme expliqué ici: AngularJS. Meilleure pratique concernant la liaison de données bidirectionnelle appropriée à partir d'un service

Quant à l'exposition à beaucoup de données, j'essaie actuellement de faire quelque chose comme ça.

// Within your view.
{{getServiceDataByKey('key')}}

// In your controller.
scope.getServiceDataByKey = service.getServiceDataByKey;

// In your service.
getServiceDataByKey : function (key) {
   return dataObject[key];
}

La raison pour laquelle je fais cela est que nous voulons garder les contrôleurs aussi propres que possible et avoir toutes nos données en un seul endroit centralisé. De plus, la plupart des données du service doivent être exposées.

1
ngr