TL;DR
1) Lorsque vous utilisez un Usine on crée un objet, on lui ajoute des propriétés, puis on retourne ce même objet. Lorsque vous passez cette fabrique dans votre contrôleur, les propriétés de l'objet seront 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 Angular l'instancie en coulisse avec le mot-clé "new". De ce fait, vous ajouterez des propriétés à 'this' et le service renverra 'this'. Lorsque vous passez le service dans votre contrôleur, les propriétés de 'this' seront désormais disponibles dans ce contrôleur par le biais de votre service.
app.controller('myServiceCtrl', function($scope, myService){
$scope.artist = myService.getArtist();
});
app.service('myService', function(){
var _artist = 'Nelly';
this.getArtist = function(){
return _artist;
}
});
Non TL;DR
1) Usine
Les usines sont le moyen le plus populaire de créer et de configurer un service. Il n'y a pas grand-chose de plus que ce que dit le TL;DR. Il suffit de créer un objet, de lui ajouter des propriétés, puis de retourner ce même objet. Ensuite, lorsque vous passez la fabrique dans votre contrôleur, les propriétés de l'objet seront désormais disponibles dans ce contrôleur via votre fabrique. Un exemple plus complet est présenté ci-dessous.
app.factory('myFactory', function(){
var service = {};
return service;
});
Maintenant, les propriétés que nous attachons à 'service' seront 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 mettrons éventuellement 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;
});
Vous remarquerez que nous ne rattachons pas ces variables/fonctions à 'service'. Nous les créons simplement afin de pouvoir les utiliser ou les modifier plus tard.
- baseUrl est l'URL de base requise par l'API iTunes.
- _artiste est l'artiste que l'on souhaite consulter.
- _finalUrl est l'URL finale et entièrement construite vers laquelle nous ferons l'appel à iTunes makeUrl est une fonction qui créera et retournera notre URL compatible avec iTunes.
Maintenant que nos variables d'aide/privées et notre fonction sont en place, ajoutons quelques propriétés à l'objet "service". Quoi que nous mettions sur 'service', nous pourrons l'utiliser directement dans n'importe quel 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 l'URL que nous avons créée. Cette méthode va renvoyer une promesse qui sera remplie une fois que les données auront été renvoyées par l'API iTunes. Si vous n'avez pas beaucoup d'expérience dans l'utilisation des promesses dans Angular, je vous recommande vivement de faire une plongée approfondie à leur sujet.
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 promesse, effectue une requête $http avec notre URL finale, puis, comme $http renvoie une promesse, nous sommes en mesure d'appeler .success ou .error après notre requête. Nous résolvons alors notre promesse avec les données iTunes, ou nous la rejetons avec un message disant 'There was an error'.
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 complète. Nous pouvons maintenant injecter 'myFactory' dans n'importe quel contrôleur et nous pourrons alors appeler les 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 le service 'myFactory'. Nous définissons ensuite les propriétés de notre objet $scope qui proviennent des données de 'myFactory'. Le seul code délicat ci-dessus est celui que vous utilisez si vous n'avez jamais eu affaire à des promesses auparavant. Étant donné que callItunes renvoie une promesse, nous sommes en mesure d'utiliser la méthode .then() et de ne définir $scope.data.artistData que lorsque notre promesse est remplie par les données iTunes. Vous remarquerez que notre contrôleur est très "fin". Toute notre logique et nos données persistantes sont situées dans notre service, et non dans notre contrôleur.
2) Service
La chose la plus importante à savoir lors de la création d'un service est qu'il est instancié avec le mot-clé "new". Pour les gourous du JavaScript, cela devrait vous donner une bonne idée de la nature du code. Pour ceux d'entre vous qui n'ont qu'une connaissance limitée de JavaScript ou pour ceux qui ne savent pas trop ce que fait le mot-clé "new", passons en revue quelques principes fondamentaux de JavaScript qui nous aideront à comprendre la nature d'un service.
Pour bien voir les changements qui se produisent lorsque vous invoquez une fonction avec le mot clé "new", créons une fonction et invoquons-la avec le mot clé "new", puis montrons ce que l'interpréteur fait lorsqu'il voit le mot clé "new". Les résultats finaux seront les mêmes.
Tout d'abord, créons notre Constructeur.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Il s'agit d'une fonction constructrice typique de JavaScript. Maintenant, chaque fois que nous invoquons la fonction Person en utilisant le mot-clé "new", "this" sera lié à l'objet nouvellement créé.
Ajoutons maintenant une méthode au prototype de notre personne afin qu'elle soit disponible pour chaque instance de notre "classe" de personne.
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 la fonction constructeur de Person et la fonction sayName sur son prototype, créons une instance de Person et appelons la fonction sayName.
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'
Ainsi, 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é "new" en JavaScript. La première chose que vous devriez remarquer est qu'après avoir utilisé 'new' dans notre exemple, nous sommes capables d'appeler une méthode (sayName) sur 'tyler' comme s'il s'agissait d'un objet - c'est parce que c'est le cas. Premièrement, nous savons que le constructeur de notre personne renvoie un objet, que cela soit visible ou non 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 la personne, l'objet que la fonction Personne renvoie doit déléguer à son prototype en cas d'échec de la recherche. En termes plus simples, lorsque nous appelons tyler.sayName(), l'interprète dit "OK, je vais chercher l'objet 'tyler' que nous venons de créer, localiser la fonction sayName, puis l'appeler. Attendez une minute, je ne la vois pas ici - tout ce que je vois est le nom et l'âge, laissez-moi vérifier le prototype. Oui, on dirait qu'elle est dans le prototype, je vais l'appeler".
Vous trouverez ci-dessous un code qui vous permettra de réfléchir à ce que le mot clé "new" fait réellement en JavaScript. Il s'agit essentiellement d'un exemple de code du paragraphe précédent. J'ai mis la "vue de l'interpréteur" ou la façon dont l'interpréteur voit le code à l'intérieur des notes.
var Person = function(name, age){
//The line below this creates an obj object 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 fait réellement le mot-clé "new" en JavaScript, la création d'un service dans Angular 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é "new". En combinant cette connaissance avec nos exemples ci-dessus, vous devriez maintenant reconnaître que vous allez attacher vos propriétés et méthodes directement à "this" qui sera ensuite retourné par le service lui-même. Voyons cela en action.
Contrairement à ce que nous avons fait à l'origine dans l'exemple Factory, nous n'avons pas besoin de créer un objet puis de le renvoyer car, comme nous l'avons déjà mentionné à plusieurs reprises, nous avons utilisé le mot-clé "new" afin que l'interpréteur crée cet objet, le délègue à son prototype, puis le renvoie pour nous sans que nous ayons à faire ce travail.
Tout d'abord, créons notre fonction "privée" et notre fonction d'aide. Cela devrait vous sembler très familier puisque nous avons fait exactement la même chose avec notre factory. Je n'expliquerai pas ici ce que fait chaque ligne, car je l'ai fait dans l'exemple de la factory. Si vous ne comprenez pas bien, relisez l'exemple de la factory.
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 à '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;
}
});
Maintenant, comme dans notre usine, setArtist, getArtist, et callItunes seront disponibles dans n'importe quel contrôleur dans lequel nous passons 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 déjà mentionné, une fois que vous comprenez vraiment ce que fait "new", les services sont presque identiques aux fabriques dans Angular.
25 votes
Possible duplicate de confused about service vs factory
4 votes
J'ai cherché "[angularjs] service factory", mais je me suis aussi souvenu qu'il y avait déjà une question à ce sujet (parce que j'avais envisagé de poser cette question moi-même à un moment donné).
2 votes
Dans une recherche, les crochets carrés signifient-ils une balise?
11 votes
@Jacob Les crochets carrés réduisent votre recherche. [angularjs] directives - recherchera les questions déjà taguées avec angularjs pour 'directives'.
0 votes
À côté de "module.service" et "module.factory", il existe 2 autres façons de créer des services en AngularJS. Pour plus d'informations, consultez mon article de blog : "Comment créer des services AngularJS (singleton) de 4 façons différentes".
0 votes
Possible duplicate de Service vs provider vs factory?
1 votes
@Mahbub En d'autres termes, "oui" :)
0 votes
Possible duplicate de Confused about Service vs Factory