TL; DR
1) Коли ви використовуєте Factory, ви створюєте об'єкт, додаєте до нього властивості та повертаєте цей самий об’єкт. Коли ви передасте цю фабрику у свій контролер, ці властивості об’єкта тепер будуть доступні в цьому контролері через вашу фабрику.
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) Коли ви користуєтесь службою , Angular створює її за кадром за допомогою "нового" ключового слова. Через це ви додасте властивості до "цього", і служба поверне "це". Коли ви передасте послугу в свій контролер, ці властивості на "це" тепер будуть доступні на цьому контролері через вашу службу.
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) Заводські
фабрики - найпопулярніший спосіб створення та налаштування послуги. Дійсно не набагато більше, ніж те, що сказав TL; DR. Ви просто створюєте об'єкт, додаєте до нього властивості, а потім повертаєте той самий об’єкт. Потім, коли ви передасте завод у свій контролер, ці властивості об’єкта тепер будуть доступні в цьому контролері через вашу фабрику. Більш обширний приклад наведено нижче.
app.factory('myFactory', function(){
var service = {};
return service;
});
Тепер будь-які властивості, які ми надаємо до "служби", будуть нам доступні, коли ми передамо "myFactory" в наш контролер.
Тепер додамо кілька "приватних" змінних до нашої функції зворотного дзвінка. Вони не будуть доступні безпосередньо від контролера, але ми зрештою встановимо кілька методів getter / setter на "service", щоб мати можливість змінювати ці "приватні" змінні при необхідності.
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;
});
Тут ви помітите, що ми не прив'язуємо ці змінні / функції до "служби". Ми просто створюємо їх для того, щоб пізніше їх використовувати чи змінювати.
- baseUrl - це базова URL-адреса, необхідна API iTunes
- _artist - художник, якого ми хочемо знайти
- _finalUrl - це остаточна і повністю вбудована URL-адреса, до якої ми здійснимо виклик до iTunes makeUrl - це функція, яка створить та поверне нашу iTunes дружню URL-адресу.
Тепер, коли наші помічникові / приватні змінні та функціонують на місці, давайте додамо деякі властивості до об’єкта 'service'. Що б ми не поставили на "послугу", ми зможемо безпосередньо використовувати в тому контролері, в який ми передамо "myFactory".
Ми створимо методи setArtist і getArtist, які просто повертають або встановлюють виконавця. Ми також створимо метод, який викликатиме API iTunes за допомогою створеної нами URL-адреси. Цей метод поверне обіцянку, яка виконається, коли дані повернуться з iTunes API. Якщо у вас не було великого досвіду використання обіцянок у Angular, я настійно рекомендую зробити глибоке занурення у них.
Нижче setArtist приймає виконавця та дозволяє встановити виконавця. getArtist повертає виконавцю callItunes перші дзвінки makeUrl (), щоб створити URL-адресу, яку ми будемо використовувати з нашим $ http-запитом. Потім він встановлює об'єкт обіцянки, робить $ http запит з нашою остаточною URL-адресою, і тому, що $ http повертає обіцянку, ми можемо викликати .success або .error після нашого запиту. Потім ми вирішуємо свою обіцянку за допомогою даних iTunes або відхиляємо її повідомленням "Виникла помилка".
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;
});
Зараз наша фабрика завершена. Тепер ми можемо ввести 'myFactory' у будь-який контролер, і тоді ми зможемо викликати наші методи, які ми приєднали до нашого сервісного об’єкта (setArtist, getArtist та 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);
})
}
});
У контролері вище ми вводимо в службу "myFactory". Потім ми встановлюємо властивості для нашого об'єкта $ range, які надходять із даних "myFactory". Єдиний хитрий код вище - якщо ви ніколи раніше не займалися обіцянками. Оскільки callItunes повертає обіцянку, ми можемо скористатися методом .then () і встановити лише $ range.data.artistData, як тільки наша обіцянка буде виконана з даними iTunes. Ви помітите, що наш контролер дуже "тонкий". Всі наші логічні та стійкі дані знаходяться в нашій службі, а не в нашому контролері.
2) Сервіс
Мабуть, найбільше, що потрібно знати при створенні Служби, - це те, що вона створена "новим" ключовим словом. Для вас, гуру JavaScript, це повинно дати вам великий натяк на природу коду. Для тих із вас, хто має обмежений досвід роботи в JavaScript, або для тих, хто не надто знайомий з тим, що насправді має "нове" ключове слово, давайте розглянемо деякі основи JavaScript, які з часом допоможуть нам зрозуміти природу Сервісу.
Щоб дійсно побачити зміни, які виникають, коли ви викликаєте функцію за допомогою ключового слова "new", давайте створимо функцію та позовимо її за допомогою "new" ключового слова, тоді покажемо, що робить інтерпретатор, коли бачить "new" ключове слово. Кінцеві результати будуть однаковими.
Спочатку давайте створимо наш Конструктор.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Це типова функція конструктора JavaScript. Тепер, коли ми викликаємо функцію Person, використовуючи ключове слово "new", "це" буде прив'язане до новоствореного об'єкта.
Тепер додамо метод до прототипу нашого Person, щоб він був доступний у всіх екземплярах нашого класу Person.
Person.prototype.sayName = function(){
alert('My name is ' + this.name);
}
Тепер, оскільки ми поклали функцію sayName на прототип, кожен екземпляр Person зможе викликати функцію sayName, щоб оповістити ім'я цього екземпляра.
Тепер, коли у нас в прототипі є функція конструктора Person і наша функція sayName, давайте створимо екземпляр Person, а потім викличемо функцію sayName.
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'
Отже, все разом код для створення конструктора Person, додавання функції до його прототипу, створення екземпляра Person, а потім виклик функції в її прототипі виглядає приблизно так.
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'
Тепер давайте розглянемо, що насправді відбувається, коли ви використовуєте "нове" ключове слово в JavaScript. Перше, що ви повинні зауважити, це те, що, використовуючи «new» у нашому прикладі, ми можемо викликати метод (sayName) на «tyler» так само, як якщо б це був об’єкт - це тому, що це так. Отже, спочатку ми знаємо, що наш конструктор Person повертає об'єкт, можемо ми бачити це в коді чи ні. По-друге, ми знаємо, що оскільки наша функція sayName розташована на прототипі, а не безпосередньо в екземплярі Person, об'єкт, який повертає функція Person, повинен бути делегований своєму прототипу при невдалих пошуках. Простіше кажучи, коли ми називаємо tyler.sayName () інтерпретатор каже: «Добре, я перегляну об’єкт« tyler », який ми тільки що створили, знайдіть функцію sayName, а потім зателефонуйте їй. Почекайте хвилину, я не бачу тут - все, що я бачу, це ім'я та вік, дозвольте перевірити прототип. Так, схоже на прототип, дозвольте мені це назвати ».
Нижче наведено код того, як ви можете подумати про те, що насправді працює нове ключове слово в JavaScript. Це в основному приклад коду вищевказаного абзацу. Я поставив "погляд інтерпретатора" або те, як перекладач бачить код всередині приміток.
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;
}
Тепер, маючи це знання про те, що "нове" ключове слово насправді робить у JavaScript, легше зрозуміти створення сервісу в Angular.
Найголовніше, що потрібно розуміти під час створення Служби - це знати, що Служби створені за допомогою "нового" ключового слова. Поєднуючи ці знання з нашими прикладами вище, тепер ви повинні визнати, що ви будете прив’язувати свої властивості та методи безпосередньо до "цього", який потім буде повернуто з самої Служби. Давайте розглянемо це в дії.
На відміну від того, що ми робили з фабричного прикладу, нам не потрібно створювати об'єкт, а потім повертати цей об'єкт, тому що, як уже згадувалося багато разів, ми використовували ключове слово "новий", щоб інтерпретатор створив цей об'єкт, чи його делегувати це прототип, то поверніть його нам, не маючи необхідності виконувати роботу.
Спочатку спочатку давайте створимо нашу "приватну" та допоміжну функцію. Це повинно виглядати дуже знайомо, оскільки ми зробили абсолютно те ж саме з нашою фабрикою. Я не поясню, що тут робить кожен рядок, тому що я це робив на заводському прикладі, якщо ви плутаєте, перечитайте заводський приклад.
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;
}
});
Тепер ми додамо всі наші методи, які будуть доступні в нашому контролері, до цього.
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;
}
});
Тепер так само, як на нашому заводі, setArtist, getArtist та callItunes будуть доступні в тому контролері, в який ми передамо myService. Ось контролер myService (який майже точно такий, як наш заводський контролер).
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);
})
}
});
Як я вже згадував раніше, коли ви дійсно зрозумієте, що означає "нове", Послуги майже ідентичні фабрикам у Angular.