Quelles sont les différences entre un Service
, Provider
et Factory
en AngularJS?
service.factory
. Je ne voulais pas compliquer davantage ce sujet.
Quelles sont les différences entre un Service
, Provider
et Factory
en AngularJS?
service.factory
. Je ne voulais pas compliquer davantage ce sujet.
Réponses:
De la liste de diffusion AngularJS, j'ai obtenu un fil étonnant qui explique le service vs l'usine vs le fournisseur et leur utilisation d'injection. Compilation des réponses:
Syntaxe: module.service( 'serviceName', function );
Résultat: Lorsque vous déclarez serviceName comme argument injectable, vous recevrez une instance de la fonction. En d'autres termes new FunctionYouPassedToService()
.
Syntaxe: module.factory( 'factoryName', function );
Résultat: Lorsque vous déclarez factoryName en tant qu'argument injectable, la valeur renvoyée vous sera fournie en invoquant la référence de fonction passée à module.factory .
Syntaxe: module.provider( 'providerName', function );
Résultat: Lorsque vous déclarez providerName comme argument injectable, vous recevrez (new ProviderFunction()).$get()
. La fonction constructeur est instanciée avant que la méthode $ get soit appelée - ProviderFunction
est la référence de fonction passée à module.provider.
Les fournisseurs ont l'avantage de pouvoir être configurés pendant la phase de configuration du module.
Voir ici pour le code fourni.
Voici une excellente explication supplémentaire de Misko:
provide.value('a', 123);
function Controller(a) {
expect(a).toEqual(123);
}
Dans ce cas, l'injecteur renvoie simplement la valeur telle quelle. Mais que faire si vous voulez calculer la valeur? Utilisez ensuite une usine
provide.factory('b', function(a) {
return a*2;
});
function Controller(b) {
expect(b).toEqual(246);
}
Donc factory
est de même d'une fonction qui est responsable de la création de valeur. Notez que la fonction d'usine peut demander d'autres dépendances.
Mais que se passe-t-il si vous voulez être plus OO et avoir une classe appelée Greeter?
function Greeter(a) {
this.greet = function() {
return 'Hello ' + a;
}
}
Ensuite, pour instancier, il faudrait écrire
provide.factory('greeter', function(a) {
return new Greeter(a);
});
Ensuite, nous pourrions demander «greeter» dans le contrôleur comme celui-ci
function Controller(greeter) {
expect(greeter instanceof Greeter).toBe(true);
expect(greeter.greet()).toEqual('Hello 123');
}
Mais c'est beaucoup trop verbeux. Une façon plus courte d'écrire ceci seraitprovider.service('greeter', Greeter);
Mais que faire si nous voulions configurer la Greeter
classe avant l'injection? Ensuite, nous pourrions écrire
provide.provider('greeter2', function() {
var salutation = 'Hello';
this.setSalutation = function(s) {
salutation = s;
}
function Greeter(a) {
this.greet = function() {
return salutation + ' ' + a;
}
}
this.$get = function(a) {
return new Greeter(a);
};
});
Ensuite, nous pouvons le faire:
angular.module('abc', []).config(function(greeter2Provider) {
greeter2Provider.setSalutation('Halo');
});
function Controller(greeter2) {
expect(greeter2.greet()).toEqual('Halo 123');
}
Comme une note de côté, service
, factory
et value
sont tous dérivés du fournisseur.
provider.service = function(name, Class) {
provider.provide(name, function() {
this.$get = function($injector) {
return $injector.instantiate(Class);
};
});
}
provider.factory = function(name, factory) {
provider.provide(name, function() {
this.$get = function($injector) {
return $injector.invoke(factory);
};
});
}
provider.value = function(name, value) {
provider.factory(name, function() {
return value;
});
};
toEqual
et ce qu'elles greeter.Greet
sont. Pourquoi ne pas utiliser quelque chose d'un peu plus réel et relatable?
factory
/ service
/ provider
:var myApp = angular.module('myApp', []);
//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!";
};
});
//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
return {
sayHello: function() {
return "Hello, World!";
}
};
});
//provider style, full blown, configurable version
myApp.provider('helloWorld', function() {
this.name = 'Default';
this.$get = function() {
var name = this.name;
return {
sayHello: function() {
return "Hello, " + name + "!";
}
}
};
this.setName = function(name) {
this.name = name;
};
});
//hey, we can configure a provider!
myApp.config(function(helloWorldProvider){
helloWorldProvider.setName('World');
});
function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
$scope.hellos = [
helloWorld.sayHello(),
helloWorldFromFactory.sayHello(),
helloWorldFromService.sayHello()];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
{{hellos}}
</div>
</body>
this
change pas de contexte dans la $get
fonction? - vous ne faites plus référence au fournisseur instancié dans cette fonction.
this
ne change pas de contexte, en fait, car ce qui est appelé est new Provider()
. $ Get (), où Provider
est la fonction qui est passée app.provider
. C'est-à-dire qu'on l' $get()
appelle comme méthode sur le construit Provider
, donc on this
se référera Provider
comme le suggère l'exemple.
Unknown provider: helloWorldProvider <- helloWorld
en exécutant ceci localement? Commentant, même erreur pour les 2 autres exemples. Existe-t-il une configuration de fournisseur cachée? (Angular 1.0.8) - Trouvé: stackoverflow.com/questions/12339272/…
TL; DR
1) Lorsque vous utilisez une usine, vous créez un objet, lui ajoutez des propriétés, puis retournez ce même objet. Lorsque vous transmettez cette usine à votre contrôleur, ces propriétés sur l'objet seront désormais disponibles dans ce contrôleur via votre usine.
app.controller(‘myFactoryCtrl’, function($scope, myFactory){
$scope.artist = myFactory.getArtist();
});
app.factory(‘myFactory’, function(){
var _artist = ‘Shakira’;
var service = {};
service.getArtist = function(){
return _artist;
}
return service;
});
2) Lorsque vous utilisez le service , AngularJS l'instancie dans les coulisses avec le «nouveau» mot clé. Pour cette raison, vous ajouterez des propriétés à «ceci» et le service renverra «ceci». Lorsque vous transmettez le service à votre contrôleur, ces propriétés sur «ceci» seront désormais disponibles sur ce contrôleur via votre service.
app.controller(‘myServiceCtrl’, function($scope, myService){
$scope.artist = myService.getArtist();
});
app.service(‘myService’, function(){
var _artist = ‘Nelly’;
this.getArtist = function(){
return _artist;
}
});
3) Les fournisseurs sont le seul service que vous pouvez passer dans votre fonction .config (). Utilisez un fournisseur lorsque vous souhaitez fournir une configuration à l'échelle du module pour votre objet de service avant de le rendre disponible.
app.controller(‘myProvider’, function($scope, myProvider){
$scope.artist = myProvider.getArtist();
$scope.data.thingFromConfig = myProvider.thingOnConfig;
});
app.provider(‘myProvider’, function(){
//Only the next two lines are available in the app.config()
this._artist = ‘’;
this.thingFromConfig = ‘’;
this.$get = function(){
var that = this;
return {
getArtist: function(){
return that._artist;
},
thingOnConfig: that.thingFromConfig
}
}
});
app.config(function(myProviderProvider){
myProviderProvider.thingFromConfig = ‘This was set in config’;
});
Non TL; DR
1) Les
usines d' usine sont le moyen le plus utilisé pour créer et configurer un service. Il n'y a vraiment pas beaucoup plus que ce que le TL; DR a dit. Il vous suffit de créer un objet, d'y ajouter des propriétés, puis de renvoyer ce même objet. Ensuite, lorsque vous passez l'usine dans votre contrôleur, ces propriétés sur l'objet seront désormais disponibles dans ce contrôleur via votre usine. Un exemple plus détaillé est présenté ci-dessous.
app.factory(‘myFactory’, function(){
var service = {};
return service;
});
Maintenant, quelles que soient les propriétés que nous attachons au «service», nous serons disponibles lorsque nous passerons «myFactory» dans notre contrôleur.
Ajoutons maintenant quelques variables «privées» à notre fonction de rappel. Celles-ci ne seront pas directement accessibles depuis le contrôleur, mais nous finirons par mettre en place des méthodes getter / setter sur 'service' pour pouvoir modifier ces variables 'privées' si nécessaire.
app.factory(‘myFactory’, function($http, $q){
var service = {};
var baseUrl = ‘https://itunes.apple.com/search?term=’;
var _artist = ‘’;
var _finalUrl = ‘’;
var makeUrl = function(){
_artist = _artist.split(‘ ‘).join(‘+’);
_finalUrl = baseUrl + _artist + ‘&callback=JSON_CALLBACK’;
return _finalUrl
}
return service;
});
Ici, vous remarquerez que nous n'attachons pas ces variables / fonctions au «service». Nous les créons simplement pour les utiliser ou les modifier ultérieurement.
Maintenant que nos variables et fonctions auxiliaires / privées sont en place, ajoutons quelques propriétés à l'objet «service». Tout ce que nous mettons sur «service» peut être directement utilisé à l'intérieur du contrôleur dans lequel nous passons «myFactory».
Nous allons créer des méthodes setArtist et getArtist qui renvoient ou définissent simplement l'artiste. Nous allons également créer une méthode qui appellera l'API iTunes avec notre URL créée. Cette méthode va retourner une promesse qui se réalisera une fois que les données seront revenues de l'API iTunes. Si vous n'avez pas beaucoup d'expérience dans l'utilisation des promesses dans AngularJS, je vous recommande fortement de les approfondir.
Ci-dessous, setArtist accepte un artiste et vous permet de définir l'artiste. getArtist renvoie l'artiste. callItunes appelle d'abord makeUrl () afin de construire l'URL que nous utiliserons avec notre requête $ http. Ensuite, il configure un objet de promesse, fait une demande $ http avec notre URL finale, puis parce que $ http renvoie une promesse, nous sommes en mesure d'appeler .success ou .error après notre demande. Nous résolvons ensuite notre promesse avec les données iTunes, ou nous la rejetons avec un message disant «Il y a eu une erreur».
app.factory('myFactory', function($http, $q){
var service = {};
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
service.setArtist = function(artist){
_artist = artist;
}
service.getArtist = function(){
return _artist;
}
service.callItunes = function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
}
return service;
});
Maintenant, notre usine est terminée. Nous pouvons désormais injecter «myFactory» dans n'importe quel contrôleur et nous pourrons ensuite appeler nos méthodes que nous avons attachées à notre objet de service (setArtist, getArtist et callItunes).
app.controller('myFactoryCtrl', function($scope, myFactory){
$scope.data = {};
$scope.updateArtist = function(){
myFactory.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myFactory.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
});
Dans le contrôleur ci-dessus, nous injectons dans le service «myFactory». Nous définissons ensuite les propriétés de notre objet $ scope avec les données de «myFactory». Le seul code délicat ci-dessus est si vous n'avez jamais traité de promesses auparavant. Parce que callItunes renvoie une promesse, nous sommes en mesure d'utiliser la méthode .then () et de définir $ scope.data.artistData uniquement une fois que notre promesse est remplie avec les données iTunes. Vous remarquerez que notre contrôleur est très «fin» (c'est une bonne pratique de codage). Toutes nos données logiques et persistantes se trouvent dans notre service, pas dans notre contrôleur.
2) Service
La chose la plus importante à savoir lors de la création d'un service est peut-être qu'il est instancié avec le «nouveau» mot clé. Pour vous, gourous de JavaScript, cela devrait vous donner une grande idée de la nature du code. Pour ceux d'entre vous qui ont peu d'expérience en JavaScript ou pour ceux qui ne connaissent pas trop ce que fait le `` nouveau '' mot clé, passons en revue certains principes fondamentaux de JavaScript qui nous aideront éventuellement à comprendre la nature d'un service.
Pour vraiment voir les changements qui se produisent lorsque vous appelez une fonction avec le mot-clé `` nouveau '', créons une fonction et appelez-la avec le mot clé `` nouveau '', puis montrons ce que fait l'interpréteur lorsqu'il voit le mot clé `` nouveau ''. Les résultats finaux seront les mêmes.
Créons d'abord notre constructeur.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Il s'agit d'une fonction constructeur JavaScript typique. Désormais, chaque fois que nous invoquerons la fonction Person à l'aide du mot-clé 'new', 'this' sera lié à l'objet nouvellement créé.
Ajoutons maintenant une méthode sur le prototype de notre Person afin qu'elle soit disponible sur chaque instance de notre 'classe' Person.
Person.prototype.sayName = function(){
alert(‘My name is ‘ + this.name);
}
Maintenant, comme nous avons placé la fonction sayName sur le prototype, chaque instance de Person pourra appeler la fonction sayName afin d'alerter le nom de cette instance.
Maintenant que nous avons notre fonction constructeur Person et notre fonction sayName sur son prototype, créons en fait une instance de Person puis appelons la fonction sayName.
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’
Donc, tous ensemble, le code pour créer un constructeur Person, ajouter une fonction à son prototype, créer une instance Person, puis appeler la fonction sur son prototype ressemble à ceci.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
alert(‘My name is ‘ + this.name);
}
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’
Voyons maintenant ce qui se passe réellement lorsque vous utilisez le «nouveau» mot clé en JavaScript. La première chose que vous devriez remarquer est qu'après avoir utilisé 'new' dans notre exemple, nous pouvons appeler une méthode (sayName) sur 'tyler' comme si c'était un objet - c'est parce que c'est le cas. Donc, tout d'abord, nous savons que notre constructeur Person retourne un objet, que nous puissions le voir dans le code ou non. Deuxièmement, nous savons que parce que notre fonction sayName est située sur le prototype et non directement sur l'instance Person, l'objet renvoyé par la fonction Person doit être délégué à son prototype en cas d'échec des recherches. En termes plus simples, lorsque nous appelons tyler.sayName (), l'interpréteur dit «OK, je vais regarder l'objet 'tyler' que nous venons de créer, localiser la fonction sayName, puis l'appeler. Attendez une minute, je ne le vois pas ici - tout ce que je vois c'est le nom et l'âge, permettez-moi de vérifier le prototype. Ouais, on dirait que c'est sur le prototype, permettez-moi de l'appeler. ”.
Vous trouverez ci-dessous un code permettant de savoir ce que le «nouveau» mot clé fait réellement en JavaScript. Il s'agit essentiellement d'un exemple de code du paragraphe ci-dessus. J'ai mis la «vue interprète» ou la façon dont l'interprète voit le code à l'intérieur des notes.
var Person = function(name, age){
//The below line creates an object(obj) that will delegate to the person’s prototype on failed lookups.
//var obj = Object.create(Person.prototype);
//The line directly below this sets ‘this’ to the newly created object
//this = obj;
this.name = name;
this.age = age;
//return this;
}
Ayant maintenant cette connaissance de ce que le «nouveau» mot clé fait vraiment en JavaScript, la création d'un service dans AngularJS devrait être plus facile à comprendre.
La chose la plus importante à comprendre lors de la création d'un service est de savoir que les services sont instanciés avec le «nouveau» mot clé. En combinant ces connaissances avec nos exemples ci-dessus, vous devez maintenant reconnaître que vous attacherez vos propriétés et méthodes directement à «ceci» qui sera ensuite renvoyé par le service lui-même. Jetons un coup d'oeil à cela en action.
Contrairement à ce que nous avons fait à l'origine avec l'exemple Factory, nous n'avons pas besoin de créer un objet puis de le renvoyer parce que, comme mentionné plusieurs fois auparavant, nous avons utilisé le mot-clé 'new' pour que l'interpréteur crée cet objet, le déléguer à c'est un prototype, puis retournez-le pour nous sans que nous ayons à faire le travail.
Tout d'abord, créons notre fonction «privée» et d'assistance. Cela devrait sembler très familier puisque nous avons fait exactement la même chose avec notre usine. Je ne vais pas expliquer ce que fait chaque ligne ici parce que je l'ai fait dans l'exemple d'usine, si vous êtes confus, relisez l'exemple d'usine.
app.service('myService', function($http, $q){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
});
Maintenant, nous allons attacher toutes nos méthodes qui seront disponibles dans notre contrôleur à «ceci».
app.service('myService', function($http, $q){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
this.setArtist = function(artist){
_artist = artist;
}
this.getArtist = function(){
return _artist;
}
this.callItunes = function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
}
});
Maintenant, tout comme dans notre usine, setArtist, getArtist et callItunes seront disponibles dans le contrôleur dans lequel nous transmettons myService. Voici le contrôleur myService (qui est presque exactement le même que notre contrôleur d'usine).
app.controller('myServiceCtrl', function($scope, myService){
$scope.data = {};
$scope.updateArtist = function(){
myService.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myService.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
});
Comme je l'ai mentionné précédemment, une fois que vous comprenez vraiment ce que le «nouveau» fait, les services sont presque identiques aux usines d'AngularJS.
3) Fournisseur
La principale chose à retenir à propos des fournisseurs est qu'ils sont le seul service que vous pouvez passer dans la partie app.config de votre application. Cela est extrêmement important si vous devez modifier une partie de votre objet de service avant qu'il ne soit disponible partout ailleurs dans votre application. Bien que très similaire aux services / usines, il y a quelques différences dont nous discuterons.
Nous avons d'abord configuré notre fournisseur de la même manière que nous l'avons fait avec notre service et notre usine. Les variables ci-dessous sont notre fonction «privée» et d'assistance.
app.provider('myProvider', function(){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
//Going to set this property on the config function below.
this.thingFromConfig = ‘’;
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
}
* Encore une fois, si une partie du code ci-dessus prête à confusion, consultez la section Usine où j'explique ce que tout cela fait plus de détails.
Vous pouvez considérer les fournisseurs comme ayant trois sections. La première section concerne les variables / fonctions «privées» qui seront modifiées / définies plus tard (voir ci-dessus). La deuxième section est les variables / fonctions qui seront disponibles dans votre fonction app.config et sont donc disponibles pour être modifiées avant d'être disponibles ailleurs (également indiqué ci-dessus). Il est important de noter que ces variables doivent être attachées au mot-clé «this». Dans notre exemple, seul 'thingFromConfig' sera disponible pour être modifié dans app.config. La troisième section (illustrée ci-dessous) comprend toutes les variables / fonctions qui seront disponibles dans votre contrôleur lorsque vous passerez le service «myProvider» à ce contrôleur spécifique.
Lors de la création d'un service avec Provider, les seules propriétés / méthodes qui seront disponibles dans votre contrôleur sont les propriétés / méthodes renvoyées par la fonction $ get (). Le code ci-dessous met $ get sur 'this' (qui, nous le savons, sera éventuellement renvoyé par cette fonction). Maintenant, cette fonction $ get renvoie toutes les méthodes / propriétés que nous voulons être disponibles dans le contrôleur. Voici un exemple de code.
this.$get = function($http, $q){
return {
callItunes: function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
},
setArtist: function(artist){
_artist = artist;
},
getArtist: function(){
return _artist;
},
thingOnConfig: this.thingFromConfig
}
}
Maintenant, le code complet du fournisseur ressemble à ceci
app.provider('myProvider', function(){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
//Going to set this property on the config function below
this.thingFromConfig = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
this.$get = function($http, $q){
return {
callItunes: function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
},
setArtist: function(artist){
_artist = artist;
},
getArtist: function(){
return _artist;
},
thingOnConfig: this.thingFromConfig
}
}
});
Maintenant, tout comme dans notre usine et notre service, setArtist, getArtist et callItunes seront disponibles dans le contrôleur dans lequel nous transmettons myProvider. Voici le contrôleur myProvider (qui est presque exactement le même que notre contrôleur d'usine / service).
app.controller('myProviderCtrl', function($scope, myProvider){
$scope.data = {};
$scope.updateArtist = function(){
myProvider.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myProvider.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
$scope.data.thingFromConfig = myProvider.thingOnConfig;
});
Comme mentionné précédemment, l'intérêt de créer un service avec Provider est de pouvoir modifier certaines variables via la fonction app.config avant que l'objet final ne soit transmis au reste de l'application. Voyons un exemple de cela.
app.config(function(myProviderProvider){
//Providers are the only service you can pass into app.config
myProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works';
});
Maintenant, vous pouvez voir comment 'thingFromConfig' est une chaîne vide dans notre fournisseur, mais quand cela apparaîtra dans le DOM, ce sera 'Cette phrase a été définie ...'.
Tous les services sont des singletons ; ils sont instanciés une fois par application. Ils peuvent être de n'importe quel type , qu'il s'agisse d'une fonction primitive, d'un littéral d'objet, ou même d'une instance d'un type personnalisé.
Le value
, factory
, service
, constant
, et les provider
méthodes sont tous les fournisseurs. Ils enseignent à l'injecteur comment instancier les services.
La recette la plus détaillée, mais aussi la plus complète, est une recette de fournisseur. Les quatre types de recettes restants - Valeur, Usine, Service et Constante - ne sont que du sucre syntaxique en plus d'une recette de fournisseur .
Vous ne devez utiliser la recette du fournisseur que lorsque vous souhaitez exposer une API pour la configuration à l'échelle de l'application qui doit être effectuée avant le démarrage de l'application. Cela n'est généralement intéressant que pour les services réutilisables dont le comportement peut devoir varier légèrement d'une application à l'autre.
decorator
.Comprendre l'usine, le service et le fournisseur AngularJS
Tous ces éléments sont utilisés pour partager des objets singleton réutilisables. Il permet de partager du code réutilisable sur votre application / divers composants / modules.
De Docs Service / Factory :
- Instancié paresseusement - Angular instancie uniquement un service / usine lorsqu'un composant d'application en dépend.
- Singletons - Chaque composant dépendant d'un service obtient une référence à l'instance unique générée par la fabrique de services.
Une fabrique est une fonction où vous pouvez manipuler / ajouter de la logique avant de créer un objet, puis l'objet nouvellement créé est renvoyé.
app.factory('MyFactory', function() {
var serviceObj = {};
//creating an object with methods/functions or variables
serviceObj.myFunction = function() {
//TO DO:
};
//return that object
return serviceObj;
});
Usage
Il peut s'agir simplement d'une collection de fonctions comme une classe. Par conséquent, il peut être instancié dans différents contrôleurs lorsque vous l'injectez dans vos fonctions contrôleur / usine / directive. Il n'est instancié qu'une seule fois par application.
Tout en regardant les services, pensez au prototype de la baie. Un service est une fonction qui instancie un nouvel objet à l'aide du mot-clé 'new'. Vous pouvez ajouter des propriétés et des fonctions à un objet de service à l'aide du this
mot clé. Contrairement à une fabrique, elle ne retourne rien (elle retourne un objet qui contient des méthodes / propriétés).
app.service('MyService', function() {
//directly binding events to this context
this.myServiceFunction = function() {
//TO DO:
};
});
Usage
Utilisez-le lorsque vous devez partager un seul objet dans l'application. Par exemple, les détails de l'utilisateur authentifié, les méthodes / données partageables, les fonctions utilitaires, etc.
Un fournisseur est utilisé pour créer un objet de service configurable. Vous pouvez configurer le paramètre de service à partir de la fonction de configuration. Il renvoie une valeur en utilisant la $get()
fonction. La $get
fonction s'exécute sur la phase d'exécution en angulaire.
app.provider('configurableService', function() {
var name = '';
//this method can be be available at configuration time inside app.config.
this.setName = function(newName) {
name = newName;
};
this.$get = function() {
var getName = function() {
return name;
};
return {
getName: getName //exposed object to where it gets injected.
};
};
});
Usage
Lorsque vous devez fournir une configuration par module pour votre objet de service avant de le rendre disponible, par exemple. supposons que vous souhaitiez définir l'URL de votre API en fonction de votre environnement dev
, stage
ouprod
REMARQUE
Seul le fournisseur sera disponible en phase de configuration angulaire, tandis que le service et l'usine ne le sont pas.
J'espère que cela a clarifié votre compréhension de l' usine, du service et du fournisseur .
only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications
, donc cela ne semble pas possible, non?
Pour moi, la révélation est venue quand j'ai réalisé qu'ils fonctionnent tous de la même manière: en exécutant quelque chose une fois , en stockant la valeur qu'ils obtiennent, puis en crachant cette même valeur stockée lorsqu'ils sont référencés via l' injection de dépendances .
Disons que nous avons:
app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);
La différence entre les trois est que:
a
La valeur stockée provient de l'exécution fn
.b
La valeur stockée vient de new
ingfn
.c
La valeur stockée provient d'abord de l'obtention d'une instance par new
ing fn
, puis de l'exécution d'une $get
méthode de l'instance.Ce qui signifie qu'il y a quelque chose comme un objet cache dans AngularJS, dont la valeur de chaque injection n'est affectée qu'une seule fois, lors de leur première injection, et où:
cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()
C'est pourquoi nous utilisons des this
services et définissons un this.$get
fournisseur.
factory
art. La seule raison pour laquelle service
il existe des langages comme CoffeeScript, TypeScript, ES6, etc., vous pouvez donc utiliser leur syntaxe de classe. Vous n'avez besoin de provider
s que si votre module est utilisé dans plusieurs applications avec des paramètres différents en utilisant app.config()
. Si votre service est un simple singleton ou est capable de créer des instances de quelque chose ne dépend que de votre implémentation.
Service vs fournisseur vs usine:
J'essaie de rester simple. Il s'agit du concept de base de JavaScript.
Tout d'abord, parlons des services dans AngularJS!
Qu'est-ce que le service: dans AngularJS, servicen'est rien d'autre qu'un objet JavaScript singleton qui peut stocker des méthodes ou des propriétés utiles. Cet objet singleton est créé par base ngApp (application angulaire) et il est partagé entre tous les contrôleurs de l'application actuelle. Lorsque Angularjs instancie un objet de service, il enregistre cet objet de service avec un nom de service unique. Ainsi, chaque fois que nous avons besoin d'une instance de service, Angular recherche dans le registre ce nom de service et renvoie la référence à l'objet de service. Tels que nous pouvons invoquer la méthode, accéder aux propriétés, etc. sur l'objet de service. Vous pouvez vous demander si vous pouvez également mettre des propriétés, des méthodes sur l'objet de portée des contrôleurs! Alors pourquoi avez-vous besoin d'un objet de service? Les réponses sont les suivantes: les services sont partagés entre plusieurs contrôleurs. Si vous placez certaines propriétés / méthodes dans un objet de portée d'un contrôleur, elles ne seront disponibles que pour la portée actuelle.
Donc, s'il y a trois portées de contrôleur, que ce soit controllerA, controllerB et controllerC, toutes partageront la même instance de service.
<div ng-controller='controllerA'>
<!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
<!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
<!-- controllerC scope -->
</div>
Comment créer un service?
AngularJS propose différentes méthodes pour enregistrer un service. Ici, nous nous concentrerons sur trois méthodes: usine (..), service (..), fournisseur (..);
Utilisez ce lien pour la référence du code
Nous pouvons définir une fonction d'usine comme ci-dessous.
factory('serviceName',function fnFactory(){ return serviceInstance;})
AngularJS fournit la méthode 'factory (' serviceName ', fnFactory)' qui prend deux paramètres, serviceName et une fonction JavaScript. Angular crée une instance de service en appelant la fonction fnFactory () comme ci-dessous.
var serviceInstace = fnFactory();
La fonction passée peut définir un objet et renvoyer cet objet. AngularJS stocke simplement cette référence d'objet dans une variable qui est passée comme premier argument. Tout ce qui est renvoyé par fnFactory sera lié à serviceInstance. Au lieu de renvoyer un objet, nous pouvons également retourner une fonction, des valeurs, etc., tout ce que nous retournerons, sera disponible pour l'instance de service.
Exemple:
var app= angular.module('myApp', []);
//creating service using factory method
app.factory('factoryPattern',function(){
var data={
'firstName':'Tom',
'lastName':' Cruise',
greet: function(){
console.log('hello!' + this.firstName + this.lastName);
}
};
//Now all the properties and methods of data object will be available in our service object
return data;
});
service('serviceName',function fnServiceConstructor(){})
C'est une autre façon, nous pouvons enregistrer un service. La seule différence est la façon dont AngularJS essaie d'instancier l'objet de service. Cette fois, angular utilise le mot-clé 'new' et appelle la fonction constructeur quelque chose comme ci-dessous.
var serviceInstance = new fnServiceConstructor();
Dans la fonction constructeur, nous pouvons utiliser le mot clé «this» pour ajouter des propriétés / méthodes à l'objet de service. exemple:
//Creating a service using the service method
var app= angular.module('myApp', []);
app.service('servicePattern',function(){
this.firstName ='James';
this.lastName =' Bond';
this.greet = function(){
console.log('My Name is '+ this.firstName + this.lastName);
};
});
La fonction Provider () est un autre moyen de créer des services. Intéressons-nous à créer un service qui affiche simplement un message de bienvenue à l'utilisateur. Mais nous voulons également fournir une fonctionnalité permettant à l'utilisateur de définir son propre message d'accueil. En termes techniques, nous voulons créer des services configurables. Comment peut-on le faire ? Il doit y avoir un moyen, afin que l'application puisse passer leurs messages d'accueil personnalisés et Angularjs le rendrait disponible pour la fonction usine / constructeur qui crée notre instance de services. Dans un tel cas, la fonction provider () fait le travail. en utilisant la fonction provider (), nous pouvons créer des services configurables.
Nous pouvons créer des services configurables en utilisant la syntaxe du fournisseur comme indiqué ci-dessous.
/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});
/*step2:configure the service */
app.config(function configureService(serviceProvider){});
1.L'objet fournisseur est créé à l'aide de la fonction constructeur que nous avons définie dans notre fonction fournisseur.
var serviceProvider = new serviceProviderConstructor();
2.La fonction que nous avons passée dans app.config (), est exécutée. C'est ce qu'on appelle la phase de configuration, et ici nous avons la possibilité de personnaliser notre service.
configureService(serviceProvider);
3.Enfin, l'instance de service est créée en appelant la méthode $ get de serviceProvider.
serviceInstance = serviceProvider.$get()
var app= angular.module('myApp', []);
app.provider('providerPattern',function providerConstructor(){
//this function works as constructor function for provider
this.firstName = 'Arnold ';
this.lastName = ' Schwarzenegger' ;
this.greetMessage = ' Welcome, This is default Greeting Message' ;
//adding some method which we can call in app.config() function
this.setGreetMsg = function(msg){
if(msg){
this.greetMessage = msg ;
}
};
//We can also add a method which can change firstName and lastName
this.$get = function(){
var firstName = this.firstName;
var lastName = this.lastName ;
var greetMessage = this.greetMessage;
var data={
greet: function(){
console.log('hello, ' + firstName + lastName+'! '+ greetMessage);
}
};
return data ;
};
});
app.config(
function(providerPatternProvider){
providerPatternProvider.setGreetMsg(' How do you do ?');
}
);
Sommaire:
Factory utilise une fonction d'usine qui renvoie une instance de service. serviceInstance = fnFactory ();
Le service utilise une fonction constructeur et Angular invoque cette fonction constructeur en utilisant le mot clé 'new' pour créer l'instance de service. serviceInstance = new fnServiceConstructor ();
Le fournisseur définit une fonction providerConstructor, cette fonction providerConstructor définit une fonction d'usine $ get . Angular appelle $ get () pour créer l'objet de service. La syntaxe du fournisseur a l'avantage supplémentaire de configurer l'objet de service avant qu'il ne soit instancié. serviceInstance = $ get ();
Comme l'ont souligné plusieurs personnes ici correctement, une usine, un fournisseur, un service et même une valeur et une constante sont des versions de la même chose. Vous pouvez disséquer le plus général provider
en chacun d'eux. Ainsi:
Voici l'article dont provient cette image:
Vous donnez une fonction à AngularJS, AngularJS mettra en cache et injectera la valeur de retour lorsque l'usine sera demandée.
Exemple:
app.factory('factory', function() {
var name = '';
// Return value **is** the object that will be injected
return {
name: name;
}
})
Usage:
app.controller('ctrl', function($scope, factory) {
$scope.name = factory.name;
});
Vous donnez une fonction à AngularJS, AngularJS appellera new pour l'instancier. C'est l'instance créée par AngularJS qui sera mise en cache et injectée lorsque le service sera demandé. Puisque new a été utilisé pour instancier le service, le mot - clé this est valide et fait référence à l'instance.
Exemple:
app.service('service', function() {
var name = '';
this.setName = function(newName) {
name = newName;
}
this.getName = function() {
return name;
}
});
Usage:
app.controller('ctrl', function($scope, service) {
$scope.name = service.getName();
});
Vous donnez à AngularJS une fonction, et AngularJS appellera sa $get
fonction. C'est la valeur de retour de la $get
fonction qui sera mise en cache et injectée lorsque le service sera demandé.
Les fournisseurs vous permettent de configurer le fournisseur avant qu'AngularJS appelle la $get
méthode pour obtenir l'injectable.
Exemple:
app.provider('provider', function() {
var name = '';
this.setName = function(newName) {
name = newName;
}
this.$get = function() {
return {
name: name
}
}
})
Utilisation (comme injectable dans un contrôleur)
app.controller('ctrl', function($scope, provider) {
$scope.name = provider.name;
});
Utilisation (la configuration du fournisseur avant $get
est appelée pour créer l'injectable)
app.config(function(providerProvider) {
providerProvider.setName('John');
});
J'ai remarqué quelque chose d'intéressant en jouant avec les fournisseurs.
La visibilité des injectables est différente pour les prestataires que pour les services et les usines. Si vous déclarez une «constante» AngularJS (par exemple, myApp.constant('a', 'Robert');
), vous pouvez l'injecter dans les services, les usines et les fournisseurs.
Mais si vous déclarez une "valeur" AngularJS (par exemple., myApp.value('b', {name: 'Jones'});
), Vous pouvez l'injecter dans les services et les usines, mais PAS dans la fonction de création de fournisseur. Vous pouvez cependant l'injecter dans la $get
fonction que vous définissez pour votre fournisseur. Ceci est mentionné dans la documentation AngularJS, mais c'est facile à manquer. Vous pouvez le trouver sur la page% provide dans les sections sur la valeur et les méthodes constantes.
<div ng-app="MyAppName">
<div ng-controller="MyCtrl">
<p>from Service: {{servGreet}}</p>
<p>from Provider: {{provGreet}}</p>
</div>
</div>
<script>
var myApp = angular.module('MyAppName', []);
myApp.constant('a', 'Robert');
myApp.value('b', {name: 'Jones'});
myApp.service('greetService', function(a,b) {
this.greeter = 'Hi there, ' + a + ' ' + b.name;
});
myApp.provider('greetProvider', function(a) {
this.firstName = a;
this.$get = function(b) {
this.lastName = b.name;
this.fullName = this.firstName + ' ' + this.lastName;
return this;
};
});
function MyCtrl($scope, greetService, greetProvider) {
$scope.servGreet = greetService.greeter;
$scope.provGreet = greetProvider.fullName;
}
</script>
C'est une partie très déroutante pour les débutants et j'ai essayé de le clarifier en termes simples
Service AngularJS: est utilisé pour partager des fonctions utilitaires avec la référence de service dans le contrôleur. Le service est de nature singleton, donc pour un service, une seule instance est créée dans le navigateur et la même référence est utilisée tout au long de la page.
Dans le service, nous créons des noms de fonction en tant que propriété avec cet objet.
AngularJS Factory: le but de Factory est également le même que Service mais dans ce cas nous créons un nouvel objet et ajoutons des fonctions comme propriétés de cet objet et à la fin nous retournons cet objet.
Fournisseur AngularJS: le but de ceci est encore le même mais le fournisseur donne la sortie de sa fonction $ get.
La définition et l'utilisation de Service, Factory et Provider sont expliquées sur http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider
Pour moi, la meilleure et la plus simple façon de comprendre la différence est:
var service, factory;
service = factory = function(injection) {}
Comment AngularJS instancie des composants particuliers (simplifié):
// service
var angularService = new service(injection);
// factory
var angularFactory = factory(injection);
Ainsi, pour le service, ce qui devient le composant AngularJS est l'instance d'objet de la classe qui est représentée par la fonction de déclaration de service. Pour l'usine, c'est le résultat renvoyé par la fonction de déclaration d'usine. L'usine peut se comporter de la même manière que le service:
var factoryAsService = function(injection) {
return new function(injection) {
// Service content
}
}
La façon la plus simple de penser est la suivante:
L'exemple de «classe» d'usine est fourni dans les commentaires, ainsi que la différence de fournisseur.
new MyService()
ou quelque chose :)
Ma clarification à ce sujet:
Fondamentalement, tous les types mentionnés (service, usine, fournisseur, etc.) ne font que créer et configurer des variables globales (qui sont bien sûr globales pour l'ensemble de l'application), tout comme les variables globales à l'ancienne.
Bien que les variables globales ne soient pas recommandées, l'utilisation réelle de ces variables globales est de fournir une injection de dépendance , en transmettant la variable au contrôleur approprié.
La création des valeurs des "variables globales" présente de nombreux niveaux de complications:
app.config
.
app.config
fichier, et cette fonction $ .get se comporte exactement comme le usine ci-dessus, en ce que sa valeur de retour est utilisée pour initialiser les variables "globales". Ma compréhension est très simple ci-dessous.
Usine: il vous suffit de créer un objet à l'intérieur de l'usine et de le renvoyer.
Un service:
Vous avez juste une fonction standard qui utilise ce mot-clé pour définir une fonction.
Fournisseur:
Il y a un $get
objet que vous définissez et il peut être utilisé pour obtenir l'objet qui renvoie des données.
Résumé des documents angulaires :
Meilleures réponses de SO:
https://stackoverflow.com/a/26924234/165673 (<- BON)
https://stackoverflow.com/a/27263882/165673
https://stackoverflow.com/a/16566144/165673
Toutes les bonnes réponses déjà. Je voudrais ajouter quelques points supplémentaires sur le service et l' usine . Avec la différence entre service / usine. Et on peut aussi avoir des questions comme:
Commençons par la différence entre le service et l'usine:
Les deux sont des singletons : chaque fois qu'Angular les trouve comme dépendance pour la première fois, il crée une seule instance de service / usine. Une fois l'instance créée, la même instance est utilisée pour toujours.
Peut être utilisé pour modéliser un objet avec un comportement : ils peuvent tous deux avoir des méthodes, des variables d'état interne, etc. Bien que la façon dont vous écrivez ce code soit différente.
Prestations de service:
Un service est une fonction constructeur, et Angular l'instanciera en appelant new yourServiceName()
. Cela signifie plusieurs choses.
this
.new yourServiceName(
), il recevra l' this
objet avec toutes les propriétés que vous lui aurez attribuées.Exemple d'échantillon:
angular.service('MyService', function() {
this.aServiceVariable = "Ved Prakash"
this.aServiceMethod = function() {
return //code
};
});
Lorsque Angular injecte ce
MyService
service dans un contrôleur qui en dépend, ce contrôleur obtiendra uneMyService
fonction sur laquelle il peut appeler des fonctions, par exemple MyService.aServiceMethod ().
Soyez prudent avecthis
:
Étant donné que le service construit est un objet, les méthodes qu'il contient peuvent s'y référer lorsqu'elles sont appelées:
angular.service('ScoreKeeper', function($http) {
this.score = 0;
this.getScore = function() {
return this.score;
};
this.setScore = function(newScore) {
this.score = newScore;
};
this.addOne = function() {
this.score++;
};
});
Vous pourriez être tenté d'appeler ScoreKeeper.setScore
dans une chaîne de promesses, par exemple si vous avez initialisé le score en le saisissant sur le serveur: $http.get('/score').then(ScoreKeeper.setScore).
le problème est que ce ScoreKeeper.setScore
sera appelé avec this
lié à null
et vous obtiendrez des erreurs. La meilleure façon serait $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))
. Que vous choisissiez de l'utiliser ou non dans vos méthodes de service, faites attention à la façon dont vous les appelez.
Renvoyer une valeur à partir d'unService
:
En raison du fonctionnement des constructeurs JavaScript, si vous renvoyez une valeur complexe à (i.e., an Object)
partir d'une constructor
fonction, l'appelant obtiendra cet objet au lieu de cette instance.
Cela signifie que vous pouvez essentiellement copier-coller l'exemple d'usine par le bas, le remplacer factory
par service
, et cela fonctionnera:
angular.service('MyService', function($http) {
var api = {};
api.aServiceMethod= function() {
return $http.get('/users');
};
return api;
});
Ainsi, lorsque Angular construit votre service avec le nouveau MyService (), il obtiendra cet objet api au lieu de l'instance MyService.
C'est le comportement pour toutes les valeurs complexes (objets, fonctions) mais pas pour les types primitifs.
Des usines:
Une usine est une ancienne fonction qui renvoie une valeur. La valeur de retour est ce qui est injecté dans des choses qui dépendent de l'usine. Un modèle d'usine typique dans Angular consiste à renvoyer un objet avec des fonctions comme propriétés, comme ceci:
angular.factory('MyFactory', function($http) {
var api = {};
api.aFactoryMethod= function() {
return $http.get('/users');
};
return api;
});
La valeur injectée pour une dépendance d'usine est la valeur de retour de l'usine, et il ne doit pas nécessairement être un objet. Cela pourrait être une fonction
Réponses aux questions 1 et 2 ci-dessus:
Pour la plupart, restez avec l'utilisation d'usines pour tout. Leur comportement est plus facile à comprendre. Il n'y a pas de choix à faire pour renvoyer une valeur ou non, et en outre, aucun bogue à introduire si vous faites la mauvaise chose.
Je les qualifie toujours de «services» quand je parle de les injecter comme des dépendances.
Le comportement du service / de l'usine est très similaire, et certaines personnes diront que l'un ou l'autre est correct. C'est un peu vrai, mais je trouve plus facile de suivre les conseils du guide de style de John Papa et de rester fidèle aux usines. **
Une précision supplémentaire est que les usines peuvent créer des fonctions / primitives, contrairement aux services. Découvrez ce jsFiddle basé sur Epokk: http://jsfiddle.net/skeller88/PxdSP/1351/ .
La fabrique renvoie une fonction qui peut être invoquée:
myApp.factory('helloWorldFromFactory', function() {
return function() {
return "Hello, World!";
};
});
La fabrique peut également renvoyer un objet avec une méthode qui peut être invoquée:
myApp.factory('helloWorldFromFactory', function() {
return {
sayHello: function() {
return "Hello, World!";
}
};
});
Le service renvoie un objet avec une méthode qui peut être invoquée:
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!";
};
});
Pour plus de détails, voir un article que j'ai écrit sur la différence: http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/
Il y a déjà de bonnes réponses, mais je veux juste partager celle-ci.
Tout d'abord: le fournisseur est le moyen / la recette pour créer unservice
(objet singleton) qui suppose être injecté par $ injector (comment AngulaJS traite le modèle IoC).
Et Value, Factory, Service et Constant (4 voies) - le sucre syntaxique par rapport à la méthode Provider / recette.
Il y a une Service vs Factory
partie a été couverte:
https://www.youtube.com/watch?v=BLzNCkPn3ao
Le service est avant tout un new
mot clé qui, comme nous le savons, fait 4 choses:
prototype
objetcontext
àthis
this
Et Factory est tout sur Factory Pattern - contient des fonctions qui renvoient des objets comme ce service.
Et cette vidéo simple / courte: couvre également le fournisseur : https://www.youtube.com/watch?v=HvTZbQ_hUZY (là vous pouvez voir comment ils vont de l'usine au fournisseur)
La recette du fournisseur est principalement utilisée dans la configuration de l'application, avant que l'application ne soit complètement démarrée / initialisée.
Après avoir lu tous ces articles, cela a créé plus de confusion pour moi .. Mais tout est toujours utile .. enfin j'ai trouvé le tableau suivant qui donnera des informations avec une comparaison simple
Et pour les débutants, comprenez: - Cela peut ne pas corriger le cas d'utilisation, mais à un niveau élevé, c'est ce qui convient à ces trois.
angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})
Pour les scénarios de base, Factory & Service se comporte de la même manière.
Voici du code de broilplate que j'ai trouvé comme modèle de code pour la fabrique d'objets dans AngularjS. J'ai utilisé un Car / CarFactory comme exemple pour illustrer. Permet un code d'implémentation simple dans le contrôleur.
<script>
angular.module('app', [])
.factory('CarFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Car = function() {
// initialize instance properties
angular.extend(this, {
color : null,
numberOfDoors : null,
hasFancyRadio : null,
hasLeatherSeats : null
});
// generic setter (with optional default value)
this.set = function(key, value, defaultValue, allowUndefined) {
// by default,
if (typeof allowUndefined === 'undefined') {
// we don't allow setter to accept "undefined" as a value
allowUndefined = false;
}
// if we do not allow undefined values, and..
if (!allowUndefined) {
// if an undefined value was passed in
if (value === undefined) {
// and a default value was specified
if (defaultValue !== undefined) {
// use the specified default value
value = defaultValue;
} else {
// otherwise use the class.prototype.defaults value
value = this.defaults[key];
} // end if/else
} // end if
} // end if
// update
this[key] = value;
// return reference to this object (fluent)
return this;
}; // end this.set()
}; // end this.Car class definition
// instance properties default values
this.Car.prototype.defaults = {
color: 'yellow',
numberOfDoors: 2,
hasLeatherSeats: null,
hasFancyRadio: false
};
// instance factory method / constructor
this.Car.prototype.instance = function(params) {
return new
this.constructor()
.set('color', params.color)
.set('numberOfDoors', params.numberOfDoors)
.set('hasFancyRadio', params.hasFancyRadio)
.set('hasLeatherSeats', params.hasLeatherSeats)
;
};
return new this.Car();
}) // end Factory Definition
.controller('testCtrl', function($scope, CarFactory) {
window.testCtrl = $scope;
// first car, is red, uses class default for:
// numberOfDoors, and hasLeatherSeats
$scope.car1 = CarFactory
.instance({
color: 'red'
})
;
// second car, is blue, has 3 doors,
// uses class default for hasLeatherSeats
$scope.car2 = CarFactory
.instance({
color: 'blue',
numberOfDoors: 3
})
;
// third car, has 4 doors, uses class default for
// color and hasLeatherSeats
$scope.car3 = CarFactory
.instance({
numberOfDoors: 4
})
;
// sets an undefined variable for 'hasFancyRadio',
// explicitly defines "true" as default when value is undefined
$scope.hasFancyRadio = undefined;
$scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);
// fourth car, purple, 4 doors,
// uses class default for hasLeatherSeats
$scope.car4 = CarFactory
.instance({
color: 'purple',
numberOfDoors: 4
});
// and then explicitly sets hasLeatherSeats to undefined
$scope.hasLeatherSeats = undefined;
$scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);
// in console, type window.testCtrl to see the resulting objects
});
</script>
Voici un exemple plus simple. J'utilise quelques bibliothèques tierces qui attendent un objet "Position" exposant la latitude et la longitude, mais via différentes propriétés d'objet. Je ne voulais pas pirater le code du fournisseur, j'ai donc ajusté les objets "Position" que je faisais circuler.
angular.module('app')
.factory('PositionFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Position = function() {
// initialize instance properties
// (multiple properties to satisfy multiple external interface contracts)
angular.extend(this, {
lat : null,
lon : null,
latitude : null,
longitude : null,
coords: {
latitude: null,
longitude: null
}
});
this.setLatitude = function(latitude) {
this.latitude = latitude;
this.lat = latitude;
this.coords.latitude = latitude;
return this;
};
this.setLongitude = function(longitude) {
this.longitude = longitude;
this.lon = longitude;
this.coords.longitude = longitude;
return this;
};
}; // end class definition
// instance factory method / constructor
this.Position.prototype.instance = function(params) {
return new
this.constructor()
.setLatitude(params.latitude)
.setLongitude(params.longitude)
;
};
return new this.Position();
}) // end Factory Definition
.controller('testCtrl', function($scope, PositionFactory) {
$scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
$scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller
;
En utilisant comme référence cette page et la documentation (qui semble s'être considérablement améliorée depuis la dernière fois que j'ai regardé), j'ai mis en place la démo du monde réel (-ish) qui utilise 4 des 5 versions du fournisseur; Valeur, constante, usine et fournisseur complet.
HTML:
<div ng-controller="mainCtrl as main">
<h1>{{main.title}}*</h1>
<h2>{{main.strapline}}</h2>
<p>Earn {{main.earn}} per click</p>
<p>You've earned {{main.earned}} by clicking!</p>
<button ng-click="main.handleClick()">Click me to earn</button>
<small>* Not actual money</small>
</div>
app
var app = angular.module('angularProviders', []);
// A CONSTANT is not going to change
app.constant('range', 100);
// A VALUE could change, but probably / typically doesn't
app.value('title', 'Earn money by clicking');
app.value('strapline', 'Adventures in ng Providers');
// A simple FACTORY allows us to compute a value @ runtime.
// Furthermore, it can have other dependencies injected into it such
// as our range constant.
app.factory('random', function randomFactory(range) {
// Get a random number within the range defined in our CONSTANT
return Math.random() * range;
});
// A PROVIDER, must return a custom type which implements the functionality
// provided by our service (see what I did there?).
// Here we define the constructor for the custom type the PROVIDER below will
// instantiate and return.
var Money = function(locale) {
// Depending on locale string set during config phase, we'll
// use different symbols and positioning for any values we
// need to display as currency
this.settings = {
uk: {
front: true,
currency: '£',
thousand: ',',
decimal: '.'
},
eu: {
front: false,
currency: '€',
thousand: '.',
decimal: ','
}
};
this.locale = locale;
};
// Return a monetary value with currency symbol and placement, and decimal
// and thousand delimiters according to the locale set in the config phase.
Money.prototype.convertValue = function(value) {
var settings = this.settings[this.locale],
decimalIndex, converted;
converted = this.addThousandSeparator(value.toFixed(2), settings.thousand);
decimalIndex = converted.length - 3;
converted = converted.substr(0, decimalIndex) +
settings.decimal +
converted.substr(decimalIndex + 1);
converted = settings.front ?
settings.currency + converted :
converted + settings.currency;
return converted;
};
// Add supplied thousand separator to supplied value
Money.prototype.addThousandSeparator = function(value, symbol) {
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, symbol);
};
// PROVIDER is the core recipe type - VALUE, CONSTANT, SERVICE & FACTORY
// are all effectively syntactic sugar built on top of the PROVIDER construct
// One of the advantages of the PROVIDER is that we can configure it before the
// application starts (see config below).
app.provider('money', function MoneyProvider() {
var locale;
// Function called by the config to set up the provider
this.setLocale = function(value) {
locale = value;
};
// All providers need to implement a $get method which returns
// an instance of the custom class which constitutes the service
this.$get = function moneyFactory() {
return new Money(locale);
};
});
// We can configure a PROVIDER on application initialisation.
app.config(['moneyProvider', function(moneyProvider) {
moneyProvider.setLocale('uk');
//moneyProvider.setLocale('eu');
}]);
// The ubiquitous controller
app.controller('mainCtrl', function($scope, title, strapline, random, money) {
// Plain old VALUE(s)
this.title = title;
this.strapline = strapline;
this.count = 0;
// Compute values using our money provider
this.earn = money.convertValue(random); // random is computed @ runtime
this.earned = money.convertValue(0);
this.handleClick = function() {
this.count ++;
this.earned = money.convertValue(random * this.count);
};
});
Démo de travail .
Cette réponse aborde le sujet / la question
OU
essentiellement ce qui se passe est
Lorsque vous créez un factory()
il définit le function
second argument que vous avez fourni au fournisseur $get
et que vous le renvoyez ( provider(name, {$get:factoryFn })
), tout ce que vous obtenez est provider
mais il n'y a pas de propriété / méthode autre que$get
celle-ci provider
(signifie que vous ne pouvez pas configurer cela)
Code source de l'usine
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
};
Lorsque vous faites un service()
retour, vous fournissez une fabrique () avec un function
qui injecte le constructor
(retourne l'instance du constructeur que vous avez fourni dans votre service) et le retourne
Code source du service
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
};
Donc, fondamentalement, dans les deux cas, vous obtenez finalement un fournisseur $ get défini sur la fonction que vous avez fournie, mais vous pouvez donner quelque chose de plus que $ get comme vous pouvez initialement le fournir dans provider () pour le bloc de configuration
Je connais beaucoup d'excellentes réponses, mais je dois partager mon expérience de l'utilisation de
1. service
pour la plupart des cas de défaut
2. factory
utilisé pour créer le service de cette instance spécifique
// factory.js ////////////////////////////
(function() {
'use strict';
angular
.module('myApp.services')
.factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];
function xFactoryImp($http) {
var fac = function (params) {
this._params = params; // used for query params
};
fac.prototype.nextPage = function () {
var url = "/_prc";
$http.get(url, {params: this._params}).success(function(data){ ...
}
return fac;
}
})();
// service.js //////////////////////////
(function() {
'use strict';
angular
.module('myApp.services')
.service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];
function xServiceImp($http) {
this._params = {'model': 'account','mode': 'list'};
this.nextPage = function () {
var url = "/_prc";
$http.get(url, {params: this._params}).success(function(data){ ...
}
}
})();
et en utilisant:
controller: ['xFactory', 'xService', function(xFactory, xService){
// books = new instance of xFactory for query 'book' model
var books = new xFactory({'model': 'book', 'mode': 'list'});
// accounts = new instance of xFactory for query 'accounts' model
var accounts = new xFactory({'model': 'account', 'mode': 'list'});
// accounts2 = accounts variable
var accounts2 = xService;
...
Un peu tard pour la fête. Mais je pensais que cela était plus utile pour ceux qui aimeraient apprendre (ou avoir de la clarté) sur le développement de services personnalisés Angular JS en utilisant les méthodologies d'usine, de service et de fournisseur.
Je suis tombé sur cette vidéo qui explique clairement les méthodologies d'usine, de service et de fournisseur pour développer AngularJS Custom Services:
https://www.youtube.com/watch?v=oUXku28ex-M
Code source: http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service
Le code affiché ici est copié directement à partir de la source ci-dessus, pour le bénéfice des lecteurs.
Le code du service personnalisé basé en usine est le suivant (qui va avec les versions sync et async avec l'appel du service http):
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcFactory',
function($scope, calcFactory) {
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function() {
//$scope.sum = calcFactory.getSum($scope.a, $scope.b); //synchronous
calcFactory.getSum($scope.a, $scope.b, function(r) { //aynchronous
$scope.sum = r;
});
};
}
]);
app.factory('calcFactory', ['$http', '$log',
function($http, $log) {
$log.log("instantiating calcFactory..");
var oCalcService = {};
//oCalcService.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//oCalcService.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
oCalcService.getSum = function(a, b, cb) { //using http service
$http({
url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp) {
$log.log(resp.data);
cb(resp.data);
}, function(resp) {
$log.error("ERROR occurred");
});
};
return oCalcService;
}
]);
Le code de la méthodologie «service» pour les services personnalisés (il est assez similaire à «usine», mais différent du point de vue de la syntaxe):
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function(){
//$scope.sum = calcService.getSum($scope.a, $scope.b);
calcService.getSum($scope.a, $scope.b, function(r){
$scope.sum = r;
});
};
}]);
app.service('calcService', ['$http', '$log', function($http, $log){
$log.log("instantiating calcService..");
//this.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//this.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
this.getSum = function(a, b, cb){
$http({
url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp){
$log.log(resp.data);
cb(resp.data);
},function(resp){
$log.error("ERROR occurred");
});
};
}]);
Le code de la méthodologie «fournisseur» pour les services personnalisés (cela est nécessaire si vous souhaitez développer un service qui pourrait être configuré):
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function(){
//$scope.sum = calcService.getSum($scope.a, $scope.b);
calcService.getSum($scope.a, $scope.b, function(r){
$scope.sum = r;
});
};
}]);
app.provider('calcService', function(){
var baseUrl = '';
this.config = function(url){
baseUrl = url;
};
this.$get = ['$log', '$http', function($log, $http){
$log.log("instantiating calcService...")
var oCalcService = {};
//oCalcService.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//oCalcService.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
oCalcService.getSum = function(a, b, cb){
$http({
url: baseUrl + '/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp){
$log.log(resp.data);
cb(resp.data);
},function(resp){
$log.error("ERROR occurred");
});
};
return oCalcService;
}];
});
app.config(['calcServiceProvider', function(calcServiceProvider){
calcServiceProvider.config("http://localhost:4467");
}]);
Enfin l'interface utilisateur qui fonctionne avec l'un des services ci-dessus:
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js" ></script>
<script type="text/javascript" src="t03.js"></script>
</head>
<body ng-app="app">
<div ng-controller="emp">
<div>
Value of a is {{a}},
but you can change
<input type=text ng-model="a" /> <br>
Value of b is {{b}},
but you can change
<input type=text ng-model="b" /> <br>
</div>
Sum = {{sum}}<br>
<button ng-click="doSum()">Calculate</button>
</div>
</body>
</html>
Juste pour clarifier les choses, à partir de la source AngularJS, vous pouvez voir qu'un service appelle simplement la fonction d'usine qui à son tour appelle la fonction de fournisseur:
function factory(name, factoryFn) {
return provider(name, { $get: factoryFn });
}
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
Discutons des trois façons de gérer la logique métier dans AngularJS de manière simple: ( Inspiré par le cours Coursera AngularJS de Yaakov )
SERVICE :
Syntaxe:
app.js
var app = angular.module('ServiceExample',[]);
var serviceExampleController =
app.controller('ServiceExampleController', ServiceExampleController);
var serviceExample = app.service('NameOfTheService', NameOfTheService);
ServiceExampleController.$inject = ['NameOfTheService'] //protects from minification of js files
function ServiceExampleController(NameOfTheService){
serviceExampleController = this;
serviceExampleController.data = NameOfTheService.getSomeData();
}
function NameOfTheService(){
nameOfTheService = this;
nameOfTheService.data = "Some Data";
nameOfTheService.getSomeData = function(){
return nameOfTheService.data;
}
}
index.html
<div ng-controller = "ServiceExampleController as serviceExample">
{{serviceExample.data}}
</div>
Caractéristiques du service:
USINE
Voyons d'abord la syntaxe:
app.js :
var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);
//first implementation where it returns a function
function NameOfTheFactoryOne(){
var factory = function(){
return new SomeService();
}
return factory;
}
//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
var factory = {
getSomeService : function(){
return new SomeService();
}
};
return factory;
}
Maintenant, en utilisant les deux ci-dessus dans le contrôleur:
var factoryOne = NameOfTheFactoryOne() //since it returns a function
factoryOne.someMethod();
var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
factoryTwo.someMethod();
Caractéristiques de l'usine:
.service()
méthode est une usine qui produit toujours le même type de service, qui est un singleton, et sans aucun moyen facile de configurer son comportement. Cette .service()
méthode est généralement utilisée comme raccourci pour quelque chose qui ne nécessite aucune configuration.FOURNISSEUR
Revoyons d'abord la syntaxe:
angular.module('ProviderModule', [])
.controller('ProviderModuleController', ProviderModuleController)
.provider('ServiceProvider', ServiceProvider)
.config(Config); //optional
Config.$inject = ['ServiceProvider'];
function Config(ServiceProvider) {
ServiceProvider.defaults.maxItems = 10; //some default value
}
ProviderModuleController.$inject = ['ServiceProvider'];
function ProviderModuleController(ServiceProvider) {
//some methods
}
function ServiceProvider() {
var provider = this;
provider.defaults = {
maxItems: 10
};
provider.$get = function () {
var someList = new someListService(provider.defaults.maxItems);
return someList;
};
}
}
Caractéristiques du fournisseur:
.service
ou l' autre des .factory
méthodes.$get
est une fonction directement attachée à l'instance de fournisseur. Cette fonction est une fonction d' usine . En d'autres termes, c'est comme celui que nous utilisons pour fournir à la .factory
méthode. Dans cette fonction, nous créons notre propre service. Cette $get
propriété, qui est une fonction, est ce qui fait du fournisseur un fournisseur . AngularJS s'attend à ce que le fournisseur ait une propriété $ get dont la valeur est une fonction qu'Angular traitera comme une fonction d'usine. Mais ce qui rend cette configuration de fournisseur très spéciale, c'est le fait que nous pouvons fournir un config
objet à l'intérieur du fournisseur de services, et cela vient généralement avec des valeurs par défaut que nous pouvons remplacer plus tard à l'étape, où nous pouvons configurer l'application entière.Usine: l'usine dans laquelle vous créez un objet à l'intérieur de l'usine et le renvoyez.
service: le service dont vous venez de disposer d'une fonction standard qui utilise le mot-clé this pour définir la fonction.
provider: Le fournisseur il y a un $ get vous définissez et il peut être utilisé pour obtenir l'objet qui retourne les données.
Essentiellement, le fournisseur, l'usine et le service sont tous des services. Une Factory est un cas particulier de Service lorsque vous n'avez besoin que d'une fonction $ get (), vous permettant de l'écrire avec moins de code.
Les principales différences entre les services, les usines et les fournisseurs sont leurs complexités. Les services sont la forme la plus simple, les usines sont un peu plus robustes et les fournisseurs sont configurables au moment de l'exécution.
Voici un résumé de l'utilisation de chacun:
Usine : La valeur que vous fournissez doit être calculée sur la base d'autres données.
Service : vous renvoyez un objet avec des méthodes.
Fournisseur : Vous voulez pouvoir configurer, pendant la phase de configuration, l'objet qui va être créé avant sa création. Utilisez le fournisseur principalement dans la configuration de l'application, avant que l'application ne soit complètement initialisée.
Les services sont des objets singleton qui sont créés lorsque cela est nécessaire et qui ne sont jamais nettoyés jusqu'à la fin du cycle de vie de l'application (lorsque le navigateur est fermé). Les contrôleurs sont détruits et nettoyés lorsqu'ils ne sont plus nécessaires.
2.La façon la plus simple de créer un service est d'utiliser la méthode factory (). La méthode factory () nous permet de définir un service en renvoyant un objet qui contient des fonctions de service et des données de service. La fonction de définition de service est l'endroit où nous plaçons nos services injectables, tels que $ http et $ q. Ex:
angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
// our factory definition
user: {},
setName: function(newName) {
service.user['name'] = newName;
},
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });
Utiliser l'usine () dans notre application
Il est facile d'utiliser l'usine dans notre application car nous pouvons simplement l'injecter là où nous en avons besoin au moment de l'exécution.
angular.module('myApp')
.controller('MainController', function($scope, User) {
$scope.saveUser = User.save;
});
Le sucre syntaxique est la différence . Seul le fournisseur est nécessaire. Ou en d'autres termes, seul le fournisseur est le véritable angulaire, tous les autres sont dérivés (pour réduire le code). Il existe également une version simple, appelée Value () qui ne renvoie que la valeur, sans calcul ni fonction. Même la valeur est dérivée du fournisseur!
Alors pourquoi de telles complications, pourquoi ne pouvons-nous pas simplement utiliser le fournisseur et oublier tout le reste? Il est censé nous aider à écrire du code facilement et à mieux communiquer. Et la réponse toungue-in-cheek serait, plus il devient complexe, meilleure sera la vente d'un cadre.
L'injection angulaire nous donne le premier indice pour arriver à cette conclusion.
"$ injector est utilisé pour récupérer les instances d'objets définies par le fournisseur " pas le service, pas la fabrique mais le fournisseur.
Et une meilleure réponse serait la suivante: "Un service angulaire est créé par une fabrique de services. Ces fabriques de services sont des fonctions qui, à leur tour, sont créées par un fournisseur de services. Les fournisseurs de services sont des fonctions de constructeur. Lorsqu'ils sont instanciés, ils doivent contenir une propriété appelé $ get, qui contient la fonction de fabrique de services. "
Donc fournisseur principal et injecteur et tout se mettra en place :). Et cela devient intéressant dans Typescript lorsque $ get peut être implémenté dans un fournisseur en héritant de IServiceProvider.