Quelles sont les différences entre une Service
, Provider
et Factory
dans AngularJS?
Sur la liste de diffusion AngularJS, j’ai obtenu n fil étonnant qui explique le service vs l’usine contre le fournisseur et leur utilisation par injection. Compiler les réponses:
Syntaxe: module.service( 'serviceName', function );
Résultat: lors de la déclaration de serviceName comme argument injectable , une instance de la fonction vous sera fournie. En d'autres termes new FunctionYouPassedToService()
.
Syntaxe: module.factory( 'factoryName', function );
Résultat: lors de la déclaration de factoryName comme argument injectable, vous recevrez la valeur renvoyée en appelant la référence de fonction transmise à module.factory .
Syntaxe: module.provider( 'providerName', function );
Résultat: lors de la déclaration de providerName en tant qu'argument injectable , vous obtiendrez (new ProviderFunction()).$get()
. La fonction constructeur est instanciée avant que la méthode $ get ne soit appelée - ProviderFunction
est la référence de la fonction transmise à 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? Ensuite, utilisez une usine
provide.factory('b', function(a) {
return a*2;
});
function Controller(b) {
expect(b).toEqual(246);
}
Donc, factory
est une fonction responsable de la création de la valeur. Notez que la fonction usine peut demander d'autres dépendances.
Mais que faire 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 serait provider.service('greeter', Greeter);
Mais si nous voulions configurer la classe Greeter
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 faire ceci:
angular.module('abc', []).config(function(greeter2Provider) {
greeter2Provider.setSalutation('Halo');
});
function Controller(greeter2) {
expect(greeter2.greet()).toEqual('Halo 123');
}
Notons que 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;
});
};
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>
TL; DR
1) Lorsque vous utilisez un Factory, vous créez un objet, ajoutez-lui des propriétés, puis renvoyez ce même objet. Lorsque vous transmettez cette fabrique à votre contrôleur, les propriétés de l'objet sont désormais disponibles dans ce contrôleur via votre fabrique.
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 Service, AngularJS l’instancie dans les coulisses avec le mot-clé "new". De ce fait, vous ajouterez des propriétés à "this" et le service renverra "this". Lorsque vous transmettez le service à votre contrôleur, les propriétés de ‘this’ 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;
}
});
)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) Usine
Les usines sont le moyen le plus populaire de créer et de configurer un service. Il n’ya vraiment pas grand chose de plus que ce que dit le TL, DR. Vous créez simplement un objet, lui ajoutez des propriétés, puis vous retournez ce même objet. Ensuite, lorsque vous transmettez la fabrique à votre contrôleur, les propriétés de l'objet sont désormais disponibles dans ce contrôleur via votre fabrique. Un exemple plus complet est ci-dessous.
app.factory(‘myFactory’, function(){
var service = {};
return service;
});
Désormais, les propriétés que nous attachons à ‘service’ seront disponibles lorsque nous transmettons ‘myFactory’ à 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 configurer certaines méthodes d’affichage/définition sur "service" afin de pouvoir modifier ces variables "privées" en cas de besoin.
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 à ‘service’. Nous les créons simplement pour pouvoir 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 en service peut être directement utilisé dans le contrôleur par lequel nous passons ‘myFactory’.
Nous allons créer les 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 renvoyer une promesse qui sera remplie une fois que les données seront revenues de l'API iTunes. Si vous n’avez pas beaucoup d’expérience dans l’utilisation de promesses dans AngularJS, je vous recommande vivement de les approfondir.
En dessous de setArtist accepte un artiste et vous permet de le définir. 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 requête $ http avec notre URL finale, puis, puisque $ http renvoie une promesse, nous pouvons appeler .success ou .error après notre requête. Nous résolvons ensuite notre promesse avec les données iTunes ou nous la rejetons avec un message disant "Il y avait 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 sommes maintenant en mesure d’injecter ‘myFactory’ dans n’importe quel contrôleur et nous pourrons ensuite appeler les méthodes que nous avons attachées à notre objet 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 difficile ci-dessus est si vous n’avez jamais tenu vos promesses auparavant. Puisque callItunes renvoie une promesse, nous pouvons utiliser la méthode .then () et définir uniquement $ scope.data.artistData une fois que notre promesse est remplie avec les données iTunes. Vous remarquerez que notre contrôleur est très "mince" (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
Peut-être que la chose la plus importante à savoir lors de la création d’un service est qu’il est instancié avec le mot-clé "nouveau". Pour vous, gourous de JavaScript, cela devrait vous donner un indice important sur la nature du code. Pour ceux d'entre vous qui ont une connaissance limitée de JavaScript ou ceux qui ne sont pas trop au courant du contenu du "nouveau" mot clé, passons en revue quelques principes fondamentaux de JavaScript qui nous aideront éventuellement à comprendre la nature d'un service.
Pour vraiment voir les changements qui surviennent lorsque vous appelez une fonction avec le mot-clé ‘nouveau’, créez une fonction et appelez-la avec le mot-clé ‘nouveau’, puis montrons ce que l’interprète fait quand il voit le mot-clé ‘nouveau’. Les résultats finaux seront les mêmes.
Commençons par créer notre constructeur.
var Person = function(name, age){
this.name = name;
this.age = age;
}
C'est une fonction constructeur JavaScript typique. Maintenant, chaque fois que nous appelons la fonction Person à l’aide du mot-clé "new", "this" sera lié au nouvel objet créé.
Ajoutons maintenant une méthode sur le prototype de notre personne afin qu’elle soit disponible sur chaque instance de notre classe de personnes.
Person.prototype.sayName = function(){
alert(‘My name is ‘ + this.name);
}
Maintenant, comme nous mettons 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 réalité une instance de Person puis appelons la fonction sayName.
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’
Donc, ensemble, le code permettant de créer un constructeur Person, d’ajouter une fonction à son prototype, de créer une instance Person, puis d’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 mot-clé "nouveau" 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. Donc, d’abord, nous savons que notre constructeur Personne renvoie un objet, que nous puissions ou non le voir dans le code. Deuxièmement, nous savons que, puisque notre fonction sayName est située sur le prototype et non directement sur l'instance de personne, l'objet renvoyé par la fonction Person doit être délégué à son prototype lors de recherches en échec. En termes plus simples, lorsque nous appelons tyler.sayName (), l’interprète dit "OK, je vais regarder sur l’objet" tyler "que nous venons de créer, recherchez la fonction sayName, puis appelez-le. Attendez une minute, je ne le vois pas ici - je ne vois que le nom et l’âge, laissez-moi vérifier le prototype. Oui, on dirait que c'est sur le prototype, laissez-moi l'appeler. ”.
Vous trouverez ci-dessous un code indiquant comment vous pouvez penser à ce que le "nouveau" mot-clé fait réellement en JavaScript. C’est fondamentalement un exemple de code du paragraphe ci-dessus. J'ai mis la "vue de l'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;
}
Maintenant que vous savez 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 mot-clé "nouveau". En combinant ces connaissances avec nos exemples ci-dessus, vous devez maintenant reconnaître que vous allez associer vos propriétés et méthodes directement à ‘this’, qui seront ensuite renvoyées par le service lui-même. Voyons 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, mais de le renvoyer, car, comme cela a été mentionné à maintes reprises, nous avons utilisé le mot clé 'new' pour que l’interprète crée cet objet et le délègue à. c'est un prototype, puis retournez-le nous sans que nous ayons à faire le travail.
Commençons par créer notre fonction "privée" et notre fonction d’aide. Cela devrait sembler très familier puisque nous avons fait exactement la même chose avec notre usine. Je n’expliquerai pas ce que chaque ligne fait ici car 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 les méthodes qui seront disponibles dans notre contrôleur à ‘this’.
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;
}
});
Désormais, comme dans notre usine, setArtist, getArtist et callItunes seront disponibles dans le contrôleur par lequel nous passons myService. Voici le contrôleur myService (qui est presque identique à 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 déjà mentionné, une fois que vous comprenez vraiment ce que fait le "nouveau", les services sont presque identiques aux usines d’AngularJS.
) Fournisseur
La chose la plus importante à retenir à propos des fournisseurs est qu’ils sont le seul service que vous pouvez transférer dans la partie app.config de votre application. Cela revêt une importance capitale 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 similaires 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 notre fonction d’aide.
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 est source de confusion, consultez la section Usine où j'explique ce que tout cela fait plus de détails.
Vous pouvez imaginer que les fournisseurs ont trois sections. La première section contient les variables/fonctions "privées" qui seront modifiées/définies ultérieurement (voir ci-dessus). La deuxième section contient les variables/fonctions qui seront disponibles dans votre fonction app.config et sont donc disponibles pour être modifiées avant d’être disponibles ailleurs (voir également 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 le fichier app.config. La troisième section (illustrée ci-dessous) regroupe toutes les variables/fonctions qui seront disponibles dans votre contrôleur lorsque vous passerez le service ‘myProvider’ dans ce contrôleur spécifique.
Lors de la création d'un service avec Fournisseur, les seules propriétés/méthodes 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 finalement 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
}
}
});
Désormais, comme dans notre usine et notre service, setArtist, getArtist et callItunes seront disponibles dans le contrôleur par lequel nous avons passé myProvider. Voici le contrôleur myProvider (qui est presque identique à 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, la création d'un service avec Provider permet de 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';
});
Vous pouvez maintenant voir comment ‘thingFromConfig’ est une chaîne vide dans notre fournisseur, mais lorsque cela apparaît dans le DOM, ce sera 'Cette phrase a été définie…'.
Comprendre la fabrique, le service et le fournisseur AngularJS
Tous ces éléments sont utilisés pour partager des objets singleton réutilisables. Il est utile de partager du code réutilisable sur votre application/divers composants/modules.
De la documentation Service/Factory :
- Instancié par la suite - Angular instancie uniquement un service/une fabrique 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 dans laquelle vous pouvez manipuler/ajouter une 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;
});
Utilisation
Ce peut être juste un ensemble 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 fois par application.
Tout en regardant les services, pensez au prototype de tableau. 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 mot clé this
. Contrairement à une fabrique, elle ne renvoie rien (elle renvoie un objet contenant des méthodes/propriétés).
app.service('MyService', function() {
//directly binding events to this context
this.myServiceFunction = function() {
//TO DO:
};
});
Utilisation
Utilisez-le lorsque vous devez partager un seul objet dans toute l'application. Par exemple, informations d'utilisateur authentifiées, méthodes/données partageables, 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 retourne une valeur en utilisant la fonction $get()
. La fonction $get
est exécutée lors de la phase d'exécution 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.
};
};
});
Utilisation
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, tel que dev
, stage
ou prod
.
NOTE
Seul le fournisseur sera disponible dans la phase de configuration angulaire, alors que le service et l’usine ne le sont pas.
J'espère que cela a éclairci votre compréhension de usine, service et fournisseur .
Pour moi, la révélation est venue quand j'ai réalisé qu'ils fonctionnaient tous de la même manière: en exécutant quelque chose une fois , en stockant la valeur qu'ils obtenaient, puis en toussant cette même valeur stockée lorsqu'elle est référencée par injection de dépendance .
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
provient de l'exécution de fn
.b
provient de new
ing fn
.c
provient du premier processus d’obtention d’une instance par new
ing fn
, puis de l’exécution d’une méthode $get
.Cela signifie qu’il s’agit d’un objet cache dans AngularJS, dont la valeur de chaque injection n’est attribuée qu’une fois, lorsqu’ils ont été injectés pour la première fois et où:
cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()
C'est pourquoi nous utilisons this
dans les services et définissons un this.$get
dans les fournisseurs.
Service vs fournisseur vs usine:
J'essaie de garder les choses simples. Tout repose sur le concept JavaScript de base.
Tout d’abord, parlons de services dans AngularJS!
Qu'est-ce que Service: Dans AngularJS, Service n'est rien d'autre qu'un objet JavaScript unique qui peut stocker des méthodes ou des propriétés utiles. Cet objet singleton est créé par ngApp (application angulaire) et il est partagé par 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 le nom de ce service dans le registre et renvoie la référence à l’objet service. De telle sorte que nous puissions appeler une méthode, des propriétés d'accès, etc. sur l'objet de service. Vous vous demandez peut-être si vous pouvez également mettre des propriétés, des méthodes sur l’objet scope des contrôleurs! Alors pourquoi avez-vous besoin d'un objet de service? Answers is: les services sont partagés par plusieurs contrôleurs. Si vous mettez des propriétés/méthodes dans l'objet scope d'un contrôleur, il ne sera disponible que pour l'étendue actuelle. Mais lorsque vous définissez des méthodes, des propriétés sur un objet de service, celui-ci sera disponible de manière globale et sera accessible dans l'étendue de tout contrôleur en injectant ce service.
Ainsi, s’il ya trois contrôleurs, qu’il s’agisse de controllerA, controllerB et controllerC, tous 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 allons nous concentrer sur trois méthodes usine (..), service (..), fournisseur (..);
tilisez 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 utilise 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 transmise peut définir un objet et le renvoyer. AngularJS stocke simplement cette référence d'objet à une variable qui est passée en premier argument. Tout ce qui est renvoyé par fnFactory sera lié à serviceInstance. Au lieu de renvoyer un objet, nous pouvons également renvoyer une fonction, des valeurs, etc. Tout ce que nous renverrons 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 l'inverse, nous pouvons enregistrer un service. La seule différence réside dans la manière dont AngularJS tente d'instancier l'objet de service. Cette fois, angular utilise le mot-clé 'new' et appelle la fonction constructeur à peu près 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. Laissons-nous nous intéresser à la création d’un service qui n’affiche que des messages de bienvenue à l’utilisateur. Mais nous souhaitons également fournir une fonctionnalité permettant à l’utilisateur de définir son propre message de bienvenue. En termes techniques, nous voulons créer des services configurables. Comment peut-on le faire ? Il doit y avoir un moyen, pour que l'application puisse transmettre leurs messages d'accueil personnalisés et qu'Angularjs le rende disponible pour la fonction fabrique/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 de fournisseur indiquée ci-dessous.
/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});
/*step2:configure the service */
app.config(function configureService(serviceProvider){});
L'objet 1.Provider est créé à l'aide de la fonction constructeur 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 nous avons ici 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 ?');
}
);
Résumé:
Factory utilise une fonction factory qui renvoie une instance de service. serviceInstance = fnFactory ();
Service utilise une fonction constructeur et Angular appelle cette fonction constructeur en utilisant le mot clé "new" pour créer l'instance de service. serviceInstance = new fnServiceConstructor ();
Fournisseur définit une fonction fournisseurConstructeur, cette fonction fournisseurConstructeur définit une fonction fabrique $ get. Angular appelle $ get () pour créer l'objet de service. La syntaxe de fournisseur présente l'avantage supplémentaire de configurer l'objet de service avant qu'il ne soit instancié. serviceInstance = $ get ();
Comme l'ont souligné à juste titre plusieurs personnes, une usine, un fournisseur, un service et même une valeur et une constante sont des versions identiques. Vous pouvez disséquer le plus général provider
en chacun d'eux. Ainsi:
Voici l'article de cette image:
Vous donnez une fonction à AngularJS, AngularJS mettra en cache et injectera la valeur de retour lorsque la fabrique est 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 à la demande du service. Depuis new a été utilisé pour instancier le service, le mot clé this est valide et se réfère à 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 une fonction à AngularJS, et AngularJS appellera sa fonction $get
. C'est la valeur de retour de la fonction $get
qui sera mise en cache et injectée à la demande du service.
Les fournisseurs vous permettent de configurer le fournisseur avant AngularJS appelle la méthode $get
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 (configuration du fournisseur avant que $get
soit appelé 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 produits injectables diffère pour les prestataires de services de celle des services et des usines. Si vous déclarez une "constante" AngularJS (par exemple, myApp.constant('a', 'Robert');
), vous pouvez l'injecter dans des services, des usines et des fournisseurs.
Mais si vous déclarez une "valeur" AngularJS (par exemple., myApp.value('b', {name: 'Jones'});
), vous pouvez l'injecter dans des services et des fabriques, mais PAS dans la fonction de création de fournisseur. Vous pouvez cependant l'injecter dans la fonction $get
que vous définissez pour votre fournisseur. Ceci est mentionné dans la documentation d'AngularJS, mais c'est facile à manquer. Vous pouvez le trouver sur la page% fourniture dans les sections consacrées aux méthodes value et constant.
<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 les fonctions utilitaires avec la référence de service dans le contrôleur. Le service est de nature singleton, ainsi, pour un service, une seule instance est créée dans le navigateur et la même référence est utilisée sur toute la page.
Dans le service, nous créons les noms de fonction en tant que propriété avec cet objet .
AngularJS Factory: le but de Factory est également identique à celui de Service, mais dans ce cas, nous créons un nouvel objet et ajoutons des fonctions en tant que propriétés de cet objet. fin nous retournons cet objet.
Fournisseur AngularJS: Le but de cette opération est à nouveau identique, mais le fournisseur donne le résultat de sa fonction $ get.
La définition et l’utilisation du service, de l’usine et du fournisseur sont expliquées à l’adresse http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider
Pour moi, le meilleur moyen 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, le composant AngularJS devient l'instance d'objet de la classe représentée par la fonction de déclaration de service. Pour l'usine, il s'agit du résultat renvoyé par la fonction de déclaration d'usine. L’usine peut se comporter comme 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 ci-dessous, ainsi que la différence de fournisseur.
Ma clarification à ce sujet:
Tous les types mentionnés (service, usine, fournisseur, etc.) ne font que créer et configurer des variables globales (bien entendu globales pour l’ensemble de l’application), tout comme les anciennes variables globales.
Bien que les variables globales ne soient pas recommandées, l'utilisation réelle de ces variables globales consiste à fournir injection de dépendance , en transmettant la variable au contrôleur approprié.
Il existe de nombreux niveaux de complications dans la création des valeurs pour les "variables globales":
app.config
.app.config
, et ce $. La fonction get se comporte comme la fabrique ci-dessus, en ce sens que sa valeur de retour est utilisée pour initialiser les variables "globales".Ma compréhension est très simple ci-dessous.
Factory: Vous créez simplement un objet à l'intérieur de la fabrique et le retournez.
Service:
Vous avez juste une fonction standard qui utilise ce mot-clé pour définir une fonction.
Fournisseur:
Vous définissez un objet $get
et vous pouvez l'utiliser pour obtenir l'objet qui renvoie les données.
Résumé de Documents angulaires :
Meilleures réponses de SO:
https://stackoverflow.com/a/26924234/16567 (<- BON) https://stackoverflow.com/a/27263882/16567
https://stackoverflow.com/a/16566144/16567
Toutes les bonnes réponses déjà. Je voudrais ajouter quelques points sur Service et sine. 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 que Angular les trouve en tant que dépendance pour la première fois, il crée une seule instance de service/fabrique. Une fois l'instance créée, la même instance est utilisée indéfiniment.
Peut être utilisé pour modéliser un objet avec un comportement: Ils peuvent avoir à la fois des méthodes, des variables d'état internes, etc. Bien que la façon dont vous écrivez ce code sera différente.
Services:
Un service est une fonction constructeur et Angular l'instanciera en appelant new yourServiceName()
. Cela signifie deux choses.
this
.new yourServiceName(
), il recevra l’objet this
avec toutes les propriétés que vous y avez définies.Exemple d'échantillon:
angular.service('MyService', function() {
this.aServiceVariable = "Ved Prakash"
this.aServiceMethod = function() {
return //code
};
});
Lorsque Angular injecte ce service
MyService
dans un contrôleur qui en dépend, ce contrôleur obtiendra unMyService
sur lequel il peut appeler des fonctions, par exemple. MyService.aServiceMethod ().
Faites attention avec this
:
Etant donné que le service construit est un objet, les méthodes qu’il contient peuvent se référer à cela quand 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 initialisiez la partition en le saisissant sur le serveur: $http.get('/score').then(ScoreKeeper.setScore).
Le problème avec ceci est que 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 ou non d'utiliser cela dans vos méthodes de service, soyez prudent, comment vous les appelez.
retour d'une valeur d'un Service
:
En raison du fonctionnement des constructeurs JavaScript, si vous renvoyez une valeur complexe (i.e., an Object)
à partir d'une fonction constructor
, l'appelant obtiendra cet objet à la place de cette instance.
Cela signifie que vous pouvez fondamentalement copier-coller l’exemple de fabrique de dessous, 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 un nouveau MyService (), il obtiendra cet objet api au lieu de l’instance MyService.
C'est le comportement de toutes les valeurs complexes (objets, fonctions) mais pas des types primitifs.
sines:
Une fabrique est une ancienne fonction qui renvoie une valeur. La valeur de retour est ce qui est injecté dans les choses qui dépendent de l’usine. Un modèle d'usine typique dans Angular consiste à renvoyer un objet avec des fonctions en tant que 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 n’est pas nécessaire que ce soit un objet. Ça pourrait être une fonction
Réponses aux questions 1 et 2 ci-dessus:
Pour la plupart, contentez-vous d'utiliser des usines pour tout. Leur comportement est plus facile à comprendre. Il n’ya pas de choix à faire pour retourner une valeur ou non, et en outre, aucun bogue à introduire si vous faites la mauvaise chose.
Je parle toujours de "services" quand je parle d’injection comme d’une dépendance, cependant.
Le comportement Service/Usine est très similaire, et certaines personnes diront que l’un ou l’autre va bien. C’est un peu vrai, mais j’ai plus de facilité à suivre les conseils du guide de style de John Papa et à me contenter des usines. **
Il y a déjà de bonnes réponses, mais je veux juste partager celle-ci.
Tout d’abord: Fournisseur est le moyen/la recette pour créer un service
(objet singleton) qui suppose d’être injecté par $ injector (comment AngulaJS s’intéresse au modèle IoC).
Et Value, Factory, Service et Constant (4 façons) - le sucre syntaxique sur Fournisseur manière/recepie.
Il y a Service vs Factory
une partie a été couverte: https://www.youtube.com/watch?v=BLzNCkPn3ao
Service concerne essentiellement new
mot-clé qui, comme nous le savons, fait 4 choses:
prototype
context
à this
this
Et Factory est tout à propos de Factory Pattern - contient des fonctions qui renvoient des objets comme ce service.
Et cette vidéo simple/courte: couvre également Fournisseur : https://www.youtube.com/watch?v=HvTZbQ_hUZY = (vous voyez ici comment ils vont d’usine à fournisseur)
Fournisseur la recette est principalement utilisée dans la configuration de l'application, avant que l'application ne soit complètement lancée/initialisée.
Une clarification supplémentaire est que les usines peuvent créer des fonctions/primitives, contrairement aux services. Découvrez ceci jsFiddle d'après Epokk: http://jsfiddle.net/skeller88/PxdSP/1351/ .
La fabrique retourne une fonction qui peut être appelée:
myApp.factory('helloWorldFromFactory', function() {
return function() {
return "Hello, World!";
};
});
La fabrique peut également renvoyer un objet avec une méthode pouvant être appelée:
myApp.factory('helloWorldFromFactory', function() {
return {
sayHello: function() {
return "Hello, World!";
}
};
});
Le service renvoie un objet avec une méthode pouvant être appelé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/
Après avoir lu tous ces articles, cela a créé plus de confusion pour moi.
Et pour les débutants comprendre: - Cela ne corrigera peut-être pas le cas d'utilisation, mais en haut niveau, c'est ce qui est utilisé pour ces trois cas.
angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})
Pour les scénarios de base, usine et service se comportent de la même manière.
Voici quelques exemples de code de plaque de grille que j'ai créés en tant que modèle de code pour la fabrique d'objets dans AngularjS. J'ai utilisé l'exemple de Car/CarFactory. Crée 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 des propriétés d'objet différentes. Je ne voulais pas pirater le code du vendeur, alors j'ai 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 grandement améliorée depuis la dernière fois que j’ai regardé), j’ai monté la démo du monde réel (-ish) suivante qui utilise 4 des 5 saveurs de 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);
};
});
Travailler démo .
Cette réponse aborde le sujet/la question
OU
essentiellement ce qui se passe est
Lorsque vous créez une factory()
, elle vous définit function
fourni en second argument à $get
du fournisseur et le renvoie (provider(name, {$get:factoryFn })
), tout ce que vous obtenez est provider
mais il n'y a pas d'autre propriété/méthode que $get
de ce provider
(signifie que vous ne pouvez pas le configurer)
Code source de l'usine
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
};
Lorsque vous créez une service()
, vous retournez une fabrique () avec un function
qui injecte le constructor
(renvoie l'instance du constructeur fourni dans votre service) et la renvoie.
Code source du service
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
};
Donc, dans les deux cas, vous obtenez éventuellement un fournisseur $ get configuré pour votre fonction que vous avez fournie, mais vous pouvez donner quelque chose de plus que $ get comme vous pouvez le fournir à l’origine dans provider () pour le bloc de configuration
Je connais une excellente réponse, mais je dois partager mon expérience de l’utilisation
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;
...
En fonction de la mémoire, les contrôleurs ne sont instanciés que lorsqu'ils sont nécessaires et sont ignorés lorsqu'ils ne le sont pas. Pour cette raison, chaque fois que vous changez de route ou rechargez une page, Angular nettoie le contrôleur actuel. Les services offrent toutefois un moyen de conserver les données pendant toute la durée de vie d'une application, tout en pouvant être utilisés de manière cohérente sur différents contrôleurs.
Angular nous offre trois façons de créer et d’enregistrer notre propre service.
1) usine
2) service
3) fournisseur
Factory: Une factory est une fonction simple qui vous permet d’ajouter de la logique avant de créer l’objet. Il retourne l'objet créé.
C'est juste une collection de fonctions comme une classe. Par conséquent, il peut être instancié dans différents contrôleurs lorsque vous l'utilisez avec une fonction constructeur.
Service: Un service est une fonction constructeur qui crée l'objet à l'aide d'un nouveau mot clé. Vous pouvez ajouter des propriétés et des fonctions à un objet de service à l'aide de ce mot clé. Contrairement à l’usine, il ne retourne rien.
C'est un objet singleton. Utilisez-le lorsque vous devez partager un seul objet dans l'application. Par exemple, les détails de l'utilisateur authentifié.
Fournisseur: Un fournisseur est utilisé pour créer un objet de service configurable. Il retourne une valeur en utilisant la fonction $ get ().
Lorsque vous devez fournir une configuration par module pour votre objet de service avant de le rendre disponible.
Exécutez le code suivant et voyez la sortie.
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body ng-controller="MyCtrl">
{{serviceOutput}}
<br/><br/>
{{factoryOutput}}
<br/><br/>
{{providerOutput}}
<script>
var app = angular.module( 'app', [] );
var MyFunc = function() {
this.name = "default name";
this.$get = function() {
this.name = "new name"
return "Hello from MyFunc.$get(). this.name = " + this.name;
};
return "Hello from MyFunc(). this.name = " + this.name;
};
// returns the actual function
app.service( 'myService', MyFunc );
// returns the function's return value
app.factory( 'myFactory', MyFunc );
// returns the output of the function's $get function
app.provider( 'myProv', MyFunc );
function MyCtrl( $scope, myService, myFactory, myProv ) {
$scope.serviceOutput = "myService = " + myService;
$scope.factoryOutput = "myFactory = " + myFactory;
$scope.providerOutput = "myProvider = " + myProv;
}
</script>
</body>
</html>
Un peu tard pour la fête. Mais j’ai pensé que c’était plus utile pour ceux qui voudraient apprendre (ou avoir plus de clarté) sur le développement de Angular JS Custom Services en utilisant des 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 des services personnalisés AngularJS:
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 directement copié de la source ci-dessus, pour le plus grand bénéfice des lecteurs.
Le code pour le service personnalisé basé sur "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 pour la méthodologie de "service" pour les services personnalisés (c'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 (nécessaire si vous souhaitez développer un service pouvant ê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, depuis la source AngularJS, vous pouvez voir qu'un service appelle simplement la fonction usine qui à son tour appelle la fonction 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 les trois manières de gérer la logique métier dans AngularJS de manière simple: (Inspiré du 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()
est une fabrique qui produit toujours le même type de service, qui est un singleton, et sans aucun moyen facile de configurer son comportement. Cette méthode .service()
est généralement utilisée comme raccourci pour quelque chose qui ne nécessite aucune configuration.FOURNISSEUR
Regardons 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 .factory
.$get
est une fonction directement liée à l'instance du fournisseur. Cette fonction est une fonction sine. En d'autres termes, c'est comme celui que nous utilisons pour fournir à la méthode .factory
. Dans cette fonction, nous créons notre propre service. Cette propriété $get
, c'est une fonction qui fait du fournisseur un fournisseur. AngularJS s'attend à ce que le fournisseur ait une propriété $ get dont la valeur est une fonction que Angular traitera comme une fonction d'usine. rend l’ensemble de cette configuration de fournisseur très spécial, c’est le fait que nous pouvons fournir un objet config
à l’intérieur du fournisseur de services, ce qui est généralement accompagné de valeurs par défaut que nous pouvons écraser ultérieurement à l’étape, où nous pouvons configurer l’application entière.Factory: L'usine vous créez réellement un objet à l'intérieur de l'usine et le retournez.
service: Le service que vous avez juste une fonction standard qui utilise le mot-clé this pour définir la fonction.
provider: Le fournisseur que vous définissez est un $ get, qui peut être utilisé pour obtenir l’objet qui renvoie les données.
Essentiellement, Fournisseur, Usine et Service sont tous des services. Une Factory est un cas particulier de Service où tout ce dont vous avez besoin est 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 leur complexité. 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 quand utiliser chacun:
Factory: La valeur que vous fournissez doit être calculée en fonction d'autres données.
Service: Vous retournez 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.
1. Les services sont des objets singleton créés le cas échéant et ne sont jamais nettoyés jusqu'à la fin du cycle de vie de l'application (date de fermeture du navigateur). Les contrôleurs sont détruits et nettoyés quand ils ne sont plus nécessaires.
2.Le moyen le plus simple de créer un service consiste à utiliser la méthode factory (). La méthode factory () nous permet de définir un service en renvoyant un objet contenant 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;
});