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 создает его за кулисами с ключевым словом «new». Из-за этого вы добавите свойства в «this», и сервис вернет «this». Когда вы передаете услугу в свой контроллер, эти свойства в «this» теперь будут доступны на этом контроллере через ваш сервис.
app.controller('myServiceCtrl', function($scope, myService){
$scope.artist = myService.getArtist();
});
app.service('myService', function(){
var _artist = 'Nelly';
this.getArtist = function(){
return _artist;
}
});
Не TL; DR
1)
Фабрики - это самый популярный способ создания и настройки сервиса. Там действительно не намного больше, чем то, что сказал TL; DR. Вы просто создаете объект, добавляете к нему свойства, а затем возвращаете тот же объект. Затем, когда вы передадите фабрику в свой контроллер, эти свойства объекта теперь будут доступны в этом контроллере через вашу фабрику. Более подробный пример приведен ниже.
app.factory('myFactory', function(){
var service = {};
return service;
});
Теперь любые свойства, которые мы прикрепляем к «сервису», будут нам доступны, когда мы передадим «myFactory» в наш контроллер.
Теперь давайте добавим некоторые «приватные» переменные в нашу функцию обратного вызова. Они не будут напрямую доступны из контроллера, но мы в конечном итоге настроим некоторые методы получения / установки для «службы», чтобы иметь возможность изменять эти «частные» переменные при необходимости.
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;
});
Здесь вы заметите, что мы не привязываем эти переменные / функцию к 'service'. Мы просто создаем их, чтобы потом использовать или модифицировать их.
- baseUrl - это базовый URL, который требуется iTunes API
- _artist - художник, которого мы хотим найти
- _finalUrl - это окончательный и полностью созданный URL-адрес, по которому мы будем обращаться к iTunes. makeUrl - это функция, которая создает и возвращает наш удобный для URL-адрес iTunes.
Теперь, когда наши вспомогательные / закрытые переменные и функции на месте, давайте добавим некоторые свойства к объекту 'service'. Что бы мы ни ставили на «сервис», мы сможем напрямую использовать тот контроллер, в который мы передаем «myFactory».
Мы собираемся создать методы setArtist и getArtist, которые просто возвращают или устанавливают художника. Мы также собираемся создать метод, который будет вызывать iTunes API с нашим созданным 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». Затем мы устанавливаем свойства для нашего объекта $ scope, которые поступают из данных из myFactory. Единственный сложный код выше, если вы никогда не имели дело с обещаниями раньше. Поскольку callItunes возвращает обещание, мы можем использовать метод .then () и устанавливать $ scope.data.artistData только после того, как наше обещание будет выполнено с данными iTunes. Вы заметите, что наш контроллер очень «тонкий». Вся наша логика и постоянные данные находятся в нашем сервисе, а не в нашем контроллере.
2) Сервис
Возможно, самая важная вещь, которую нужно знать при создании Сервиса, это то, что он создается с ключевым словом «new». Для вас, гуру JavaScript, это должно дать вам подсказку о природе кода. Для тех из вас, кто имеет ограниченный опыт работы с JavaScript, или тех, кто не слишком знаком с тем, что на самом деле делает ключевое слово «new», давайте рассмотрим некоторые основы JavaScript, которые в конечном итоге помогут нам понять природу Сервиса.
Чтобы действительно увидеть изменения, которые происходят при вызове функции с ключевым словом «new», давайте создадим функцию и вызовем ее с ключевым словом «new», а затем покажем, что делает интерпретатор, когда видит ключевое слово «new». Конечные результаты будут одинаковыми.
Сначала давайте создадим наш конструктор.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Это типичная функция конструктора JavaScript. Теперь всякий раз, когда мы вызываем функцию Person с помощью ключевого слова new, this будет привязано к вновь созданному объекту.
Теперь давайте добавим метод в прототип нашего 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'
Теперь давайте посмотрим, что на самом деле происходит, когда вы используете ключевое слово «new» в 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;
}
Теперь, имея представление о том, что на самом деле делает ключевое слово «new» в JavaScript, создание службы в Angular должно быть проще для понимания.
Самая важная вещь, которую нужно понять при создании Сервиса, это знание того, что Сервисы создаются с помощью ключевого слова «new». Объединяя эти знания с нашими примерами выше, вы теперь должны понимать, что вы будете привязывать свои свойства и методы непосредственно к «this», которое затем будет возвращено из самой Службы. Давайте посмотрим на это в действии.
В отличие от того, что мы изначально делали с примером Factory, нам не нужно создавать объект, а затем возвращать этот объект, потому что, как упоминалось много раз ранее, мы использовали ключевое слово «new», поэтому интерпретатор создаст этот объект, предоставив ему делегирование это прототип, а затем верните его нам без необходимости выполнять работу.
Прежде всего, давайте создадим нашу «приватную» и вспомогательную функцию. Это должно выглядеть очень знакомо, так как мы сделали то же самое с нашим заводом. Я не буду объяснять, что здесь делает каждая строка, потому что я сделал это в заводском примере, если вы не уверены, перечитайте заводской пример.
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».
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.