TL; DR
1) Quando si utilizza una Factory, si crea un oggetto, si aggiungono proprietà, quindi si restituisce lo stesso oggetto. Quando passi questa fabbrica nel tuo controller, quelle proprietà sull'oggetto saranno ora disponibili in quel controller attraverso la tua fabbrica.
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) Quando si utilizza Service , Angular lo crea un'istanza dietro le quinte con la "nuova" parola chiave. Per questo motivo, aggiungi proprietà a "this" e il servizio restituirà "this". Quando si passa il servizio al controller, le proprietà su "this" saranno ora disponibili su quel controller tramite il servizio.
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) Le Factory
Factory sono il modo più popolare per creare e configurare un servizio. Non c'è davvero molto di più di quello che ha detto il TL; DR. Basta creare un oggetto, aggiungere proprietà ad esso, quindi restituire lo stesso oggetto. Quindi quando passi la fabbrica nel tuo controller, quelle proprietà sull'oggetto saranno ora disponibili in quel controller attraverso la tua fabbrica. Un esempio più ampio è di seguito.
app.factory('myFactory', function(){
var service = {};
return service;
});
Ora, qualunque proprietà attribuiamo al "servizio" sarà disponibile per noi quando passiamo "myFactory" nel nostro controller.
Ora aggiungiamo alcune variabili 'private' alla nostra funzione di callback. Questi non saranno direttamente accessibili dal controller, ma alla fine imposteremo alcuni metodi getter / setter su 'service' per essere in grado di modificare queste variabili 'private' quando necessario.
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;
});
Qui noterai che non stiamo associando tali variabili / funzioni al "servizio". Li stiamo semplicemente creando per usarli o modificarli in seguito.
- baseUrl è l'URL di base richiesto dall'API di iTunes
- _artista è l'artista che desideriamo cercare
- _finalUrl è l'URL finale e completo a cui effettueremo la chiamata a iTunes makeUrl è una funzione che creerà e restituirà il nostro URL amichevole di iTunes.
Ora che le nostre variabili e funzioni helper / private sono presenti, aggiungiamo alcune proprietà all'oggetto 'service'. Qualunque cosa mettiamo in "servizio", saremo in grado di utilizzare direttamente in qualsiasi controller in cui passiamo "myFactory".
Creeremo metodi setArtist e getArtist che semplicemente restituiscono o impostano l'artista. Creeremo anche un metodo che chiamerà l'API di iTunes con il nostro URL creato. Questo metodo restituirà una promessa che manterrà una volta che i dati sono tornati dall'API di iTunes. Se non hai avuto molta esperienza nell'uso delle promesse in Angular, ti consiglio vivamente di fare un tuffo profondo su di esse.
Sotto setArtist accetta un artista e ti consente di impostare l'artista. getArtist restituisce l'artista callItunes prima chiama makeUrl () per creare l'URL che useremo con la nostra richiesta $ http. Quindi imposta un oggetto promessa, effettua una richiesta $ http con il nostro URL finale, quindi poiché $ http restituisce una promessa, siamo in grado di chiamare .success o .error dopo la nostra richiesta. Quindi risolviamo la nostra promessa con i dati di iTunes o la rifiutiamo con un messaggio che dice "Si è verificato un errore".
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;
});
Ora la nostra fabbrica è completa. Ora siamo in grado di iniettare "myFactory" in qualsiasi controller e potremo quindi chiamare i nostri metodi che abbiamo collegato al nostro oggetto di servizio (setArtist, getArtist e 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);
})
}
});
Nel controller sopra stiamo iniettando nel servizio "myFactory". Quindi impostiamo le proprietà sul nostro oggetto $ scope che provengono dai dati di 'myFactory'. L'unico codice di cui sopra è se non hai mai avuto a che fare con le promesse prima. Poiché callItunes sta restituendo una promessa, siamo in grado di utilizzare il metodo .then () e impostare $ scope.data.artistData solo dopo che la nostra promessa è stata rispettata con i dati di iTunes. Noterai che il nostro controller è molto "sottile". Tutta la nostra logica e i dati persistenti si trovano nel nostro servizio, non nel nostro controller.
2) Servizio
Forse la cosa più importante da sapere quando si ha a che fare con la creazione di un servizio è che è istanziato con la "nuova" parola chiave. Per voi guru di JavaScript questo dovrebbe darvi un grande suggerimento sulla natura del codice. Per quelli di voi con un background limitato in JavaScript o per quelli che non hanno familiarità con ciò che effettivamente fa la "nuova" parola chiave, passiamo in rassegna alcuni fondamentali di JavaScript che alla fine ci aiuteranno a comprendere la natura di un Servizio.
Per vedere davvero le modifiche che si verificano quando invochi una funzione con la parola chiave "nuova", creiamo una funzione e invocala con la parola chiave "nuova", quindi mostriamo cosa fa l'interprete quando vede la parola chiave "nuova". I risultati finali saranno entrambi uguali.
Per prima cosa creiamo il nostro costruttore.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Questa è una tipica funzione di costruzione JavaScript. Ora, ogni volta che invochiamo la funzione Persona usando la parola chiave "new", "this" verrà associato all'oggetto appena creato.
Ora aggiungiamo un metodo sul prototipo della nostra Persona in modo che sia disponibile su ogni istanza della nostra "classe".
Person.prototype.sayName = function(){
alert('My name is ' + this.name);
}
Ora, poiché mettiamo la funzione sayName sul prototipo, ogni istanza di Person sarà in grado di chiamare la funzione sayName per avvisare il nome dell'istanza.
Ora che abbiamo la nostra funzione di costruzione Person e la nostra funzione sayName sul suo prototipo, creiamo effettivamente un'istanza di Person quindi chiamiamo la funzione sayName.
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'
Quindi tutti insieme il codice per creare un costruttore Person, aggiungere una funzione al suo prototipo, creare un'istanza Person e quindi chiamare la funzione sul suo prototipo appare così.
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'
Ora diamo un'occhiata a ciò che sta realmente accadendo quando usi la "nuova" parola chiave in JavaScript. La prima cosa che dovresti notare è che dopo aver usato 'new' nel nostro esempio, siamo in grado di chiamare un metodo (sayName) su 'tyler' proprio come se fosse un oggetto - è perché lo è. Quindi, per prima cosa, sappiamo che il nostro costruttore Person sta restituendo un oggetto, che possiamo vedere o meno nel codice. In secondo luogo, sappiamo che poiché la nostra funzione sayName si trova sul prototipo e non direttamente sull'istanza Person, l'oggetto che la funzione Person sta restituendo deve delegare al suo prototipo in caso di ricerche non riuscite. In termini più semplici, quando chiamiamo tyler.sayName () l'interprete dice “OK, cercherò l'oggetto 'tyler' che abbiamo appena creato, localizziamo la funzione sayName, quindi la chiamiamo. Aspetta un minuto, non lo vedo qui - tutto ciò che vedo è il nome e l'età, fammi controllare il prototipo. Sì, sembra che sia sul prototipo, lascia che lo chiami. ”.
Di seguito è riportato il codice su come pensare a ciò che la "nuova" parola chiave sta effettivamente facendo in JavaScript. È fondamentalmente un esempio di codice del paragrafo precedente. Ho inserito la "vista dell'interprete" o il modo in cui l'interprete vede il codice all'interno delle note.
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;
}
Ora avendo questa conoscenza di ciò che la "nuova" parola chiave fa realmente in JavaScript, la creazione di un servizio in angolare dovrebbe essere più facile da capire.
La cosa più importante da capire quando si crea un servizio è sapere che i servizi sono istanziati con la "nuova" parola chiave. Combinando questa conoscenza con i nostri esempi precedenti, ora dovresti riconoscere che alle tue proprietà e ai tuoi metodi collegherai direttamente "questo", che verrà quindi restituito dal Servizio stesso. Diamo un'occhiata a questo in azione.
A differenza di quello che abbiamo fatto inizialmente con l'esempio Factory, non abbiamo bisogno di creare un oggetto per restituirlo, perché, come menzionato molte volte in precedenza, abbiamo usato la parola chiave "new" in modo che l'interprete creerà quell'oggetto e ne faccia delegare è un prototipo, quindi restituiscilo per noi senza che dobbiamo fare il lavoro.
Per prima cosa, creiamo la nostra funzione "privata" e di supporto. Questo dovrebbe sembrare molto familiare poiché abbiamo fatto esattamente la stessa cosa con la nostra fabbrica. Non spiegherò cosa fa ogni riga qui perché l'ho fatto nell'esempio di fabbrica, se sei confuso, rileggi l'esempio di fabbrica.
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;
}
});
Ora allegheremo tutti i nostri metodi che saranno disponibili nel nostro controller a "questo".
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;
}
});
Proprio come nella nostra fabbrica, setArtist, getArtist e callItunes saranno disponibili in qualsiasi controller in cui passiamo myService. Ecco il controller myService (che è quasi identico al nostro controller di fabbrica).
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);
})
}
});
Come ho detto prima, una volta che capisci davvero cosa fa il "nuovo", i Servizi sono quasi identici alle fabbriche in Angular.