TL; DR
1) Wenn Sie eine Factory verwenden , erstellen Sie ein Objekt, fügen Eigenschaften hinzu und geben dasselbe Objekt zurück. Wenn Sie diese Factory an Ihren Controller übergeben, sind diese Eigenschaften für das Objekt jetzt in diesem Controller über Ihre Factory verfügbar.
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) Wenn Sie Service verwenden , instanziiert Angular ihn hinter den Kulissen mit dem Schlüsselwort 'new'. Aus diesem Grund fügen Sie 'this' Eigenschaften hinzu, und der Dienst gibt 'this' zurück. Wenn Sie den Dienst an Ihren Controller übergeben, sind diese Eigenschaften für "this" jetzt über Ihren Dienst auf diesem Controller verfügbar.
app.controller('myServiceCtrl', function($scope, myService){
$scope.artist = myService.getArtist();
});
app.service('myService', function(){
var _artist = 'Nelly';
this.getArtist = function(){
return _artist;
}
});
Nicht TL; DR
1) Factory
Factories sind die beliebteste Methode zum Erstellen und Konfigurieren eines Dienstes. Es gibt wirklich nicht viel mehr als das, was die TL gesagt hat; DR. Sie erstellen einfach ein Objekt, fügen ihm Eigenschaften hinzu und geben dasselbe Objekt zurück. Wenn Sie dann die Factory an Ihren Controller übergeben, sind diese Eigenschaften für das Objekt jetzt in diesem Controller über Ihre Factory verfügbar. Ein ausführlicheres Beispiel finden Sie unten.
app.factory('myFactory', function(){
var service = {};
return service;
});
Jetzt stehen uns alle Eigenschaften zur Verfügung, die wir an 'service' anhängen, wenn wir 'myFactory' an unseren Controller übergeben.
Fügen wir nun unserer Rückruffunktion einige 'private' Variablen hinzu. Auf diese kann vom Controller aus nicht direkt zugegriffen werden, aber wir werden eventuell einige Getter / Setter-Methoden für 'service' einrichten, um diese 'privaten' Variablen bei Bedarf ändern zu können.
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;
});
Hier werden Sie feststellen, dass wir diese Variablen / Funktionen nicht an 'service' anhängen. Wir erstellen sie einfach, um sie später entweder zu verwenden oder zu ändern.
- baseUrl ist die Basis-URL, die die iTunes-API benötigt
- _artist ist der Künstler, nach dem wir suchen möchten
- _finalUrl ist die endgültige und vollständig erstellte URL, zu der wir iTunes aufrufen. makeUrl ist eine Funktion, mit der unsere iTunes-freundliche URL erstellt und zurückgegeben wird.
Nachdem unsere Hilfs- / privaten Variablen und Funktionen vorhanden sind, fügen wir dem 'service'-Objekt einige Eigenschaften hinzu. Was auch immer wir auf "Service" setzen, wir können es direkt in dem Controller verwenden, an den wir "myFactory" übergeben.
Wir werden setArtist- und getArtist-Methoden erstellen, die den Künstler einfach zurückgeben oder festlegen. Wir werden auch eine Methode erstellen, die die iTunes-API mit unserer erstellten URL aufruft. Diese Methode wird ein Versprechen zurückgeben, das erfüllt wird, sobald die Daten von der iTunes-API zurückgegeben wurden. Wenn Sie nicht viel Erfahrung mit Versprechungen in Angular haben, empfehle ich Ihnen dringend, sich eingehend mit ihnen zu befassen.
Unten akzeptiert setArtist einen Künstler und ermöglicht es Ihnen, den Künstler festzulegen . getArtist gibt den Künstler zurück. callItunes ruft zuerst makeUrl () auf, um die URL zu erstellen, die wir für unsere $ http-Anfrage verwenden. Anschließend wird ein Versprechungsobjekt eingerichtet, eine $ http-Anfrage mit unserer endgültigen URL gestellt. Da $ http ein Versprechen zurückgibt, können wir nach unserer Anfrage .success oder .error aufrufen. Wir lösen dann unser Versprechen mit den iTunes-Daten oder lehnen es mit der Meldung "Es ist ein Fehler aufgetreten" ab.
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;
});
Jetzt ist unsere Fabrik fertig. Wir können jetzt 'myFactory' in jeden Controller einfügen und dann unsere Methoden aufrufen, die wir an unser Serviceobjekt angehängt haben (setArtist, getArtist und 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);
})
}
});
Im obigen Controller injizieren wir den 'myFactory'-Dienst. Wir legen dann Eigenschaften für unser $ scope-Objekt fest, die aus Daten von 'myFactory' stammen. Der einzige schwierige Code oben ist, wenn Sie sich noch nie mit Versprechungen befasst haben. Da callItunes ein Versprechen zurückgibt, können wir die .then () -Methode verwenden und $ scope.data.artistData erst festlegen, wenn unser Versprechen mit den iTunes-Daten erfüllt ist. Sie werden feststellen, dass unser Controller sehr dünn ist. Alle unsere logischen und persistenten Daten befinden sich in unserem Service, nicht in unserem Controller.
2) Service
Das vielleicht Wichtigste, was Sie beim Erstellen eines Dienstes wissen müssen, ist, dass er mit dem Schlüsselwort "Neu" instanziiert wird. Für Ihre JavaScript-Gurus sollte dies einen großen Hinweis auf die Art des Codes geben. Für diejenigen unter Ihnen mit eingeschränktem Hintergrund in JavaScript oder für diejenigen, die nicht genau wissen, was das 'neue' Schlüsselwort tatsächlich bewirkt, lassen Sie uns einige JavaScript-Grundlagen überprüfen, die uns letztendlich helfen, die Natur eines Dienstes zu verstehen.
Um die Änderungen wirklich zu sehen, die auftreten, wenn Sie eine Funktion mit dem Schlüsselwort 'new' aufrufen, erstellen wir eine Funktion und rufen sie mit dem Schlüsselwort 'new' auf. Zeigen wir dann, was der Interpreter tut, wenn er das Schlüsselwort 'new' sieht. Die Endergebnisse sind beide gleich.
Lassen Sie uns zuerst unseren Konstruktor erstellen.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Dies ist eine typische JavaScript-Konstruktorfunktion. Wenn wir nun die Person-Funktion mit dem Schlüsselwort 'new' aufrufen, wird 'this' an das neu erstellte Objekt gebunden.
Fügen wir nun dem Prototyp unserer Person eine Methode hinzu, damit sie für jede Instanz unserer Personenklasse verfügbar ist.
Person.prototype.sayName = function(){
alert('My name is ' + this.name);
}
Da wir nun die Funktion sayName auf den Prototyp setzen, kann jede Instanz von Person die Funktion sayName aufrufen, um den Namen dieser Instanz zu warnen.
Nachdem wir nun unsere Person-Konstruktorfunktion und unsere sayName-Funktion in ihrem Prototyp haben, erstellen wir tatsächlich eine Instanz von Person und rufen dann die sayName-Funktion auf.
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'
Insgesamt sieht der Code zum Erstellen eines Personenkonstruktors, zum Hinzufügen einer Funktion zum Prototyp, zum Erstellen einer Personeninstanz und zum anschließenden Aufrufen der Funktion für den Prototyp folgendermaßen aus.
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'
Schauen wir uns nun an, was tatsächlich passiert, wenn Sie das Schlüsselwort 'new' in JavaScript verwenden. Das erste, was Sie beachten sollten, ist, dass wir nach der Verwendung von 'new' in unserem Beispiel eine Methode (sayName) für 'tyler' aufrufen können, als wäre es ein Objekt - das liegt daran, dass es so ist. Zuerst wissen wir also, dass unser Personenkonstruktor ein Objekt zurückgibt, ob wir das im Code sehen können oder nicht. Zweitens wissen wir, dass das Objekt, das die Person-Funktion zurückgibt, bei fehlgeschlagenen Suchvorgängen an ihren Prototyp delegieren muss, da sich unsere sayName-Funktion auf dem Prototyp und nicht direkt auf der Person-Instanz befindet. Einfacher ausgedrückt, wenn wir tyler.sayName () aufrufen, sagt der Interpreter: „OK, ich werde das soeben erstellte 'tyler'-Objekt betrachten, die Funktion sayName suchen und es dann aufrufen. Moment mal, ich sehe es hier nicht - alles was ich sehe ist Name und Alter, Lassen Sie mich den Prototyp überprüfen. Ja, es sieht so aus, als wäre es auf dem Prototyp, lass es mich nennen. “
Unten finden Sie Code, wie Sie darüber nachdenken können, was das 'neue' Schlüsselwort in JavaScript tatsächlich tut. Es ist im Grunde ein Codebeispiel für den obigen Absatz. Ich habe die 'Interpreter-Ansicht' oder die Art und Weise, wie der Interpreter den Code sieht, in Notizen eingefügt.
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;
}
Wenn Sie nun wissen, was das 'neue' Schlüsselwort in JavaScript wirklich bewirkt, sollte es einfacher sein, einen Dienst in Angular zu erstellen.
Das Wichtigste, was Sie beim Erstellen eines Dienstes verstehen müssen, ist zu wissen, dass Dienste mit dem Schlüsselwort "Neu" instanziiert werden. Wenn Sie dieses Wissen mit unseren obigen Beispielen kombinieren, sollten Sie jetzt erkennen, dass Sie Ihre Eigenschaften und Methoden direkt an 'this' anhängen, das dann vom Service selbst zurückgegeben wird. Schauen wir uns das in Aktion an.
Im Gegensatz zu dem, was wir ursprünglich mit dem Factory-Beispiel gemacht haben, müssen wir kein Objekt erstellen und dann dieses Objekt zurückgeben, da wir, wie bereits mehrfach erwähnt, das Schlüsselwort 'new' verwendet haben, damit der Interpreter dieses Objekt erstellt und es delegieren lässt Es ist ein Prototyp und wird dann für uns zurückgegeben, ohne dass wir die Arbeit erledigen müssen.
Lassen Sie uns zuerst unsere 'private' und Hilfsfunktion erstellen. Dies sollte sehr vertraut aussehen, da wir mit unserer Fabrik genau dasselbe gemacht haben. Ich werde hier nicht erklären, was jede Zeile tut, da ich das im Fabrikbeispiel getan habe. Wenn Sie verwirrt sind, lesen Sie das Fabrikbeispiel erneut.
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;
}
});
Jetzt werden wir alle unsere Methoden, die in unserem Controller verfügbar sein werden, an 'this' anhängen.
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;
}
});
Genau wie in unserer Factory sind setArtist, getArtist und callItunes jetzt in jedem Controller verfügbar, an den wir myService übergeben. Hier ist der myService-Controller (der fast genau dem unseres werkseitigen Controllers entspricht).
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);
})
}
});
Wie ich bereits erwähnt habe, sind Services, sobald Sie wirklich verstanden haben, was "neu" macht, fast identisch mit Fabriken in Angular.