Які відмінності між Service
, Provider
і Factory
в AngularJS?
service.factory
. Не хотіли більше ускладнювати цю тему.
Які відмінності між Service
, Provider
і Factory
в AngularJS?
service.factory
. Не хотіли більше ускладнювати цю тему.
Відповіді:
Із списку розсилки AngularJS я отримав дивовижну нитку, яка пояснює службу проти фабрики проти постачальника та використання їх для ін'єкцій. Складання відповідей:
Синтаксис: module.service( 'serviceName', function );
Результат: При оголошенні serviceName як аргументу, який можна ввести, вам буде наданий екземпляр функції. Іншими словами new FunctionYouPassedToService()
.
Синтаксис: module.factory( 'factoryName', function );
Результат: При оголошенні factoryName як аргументу, що ін'єктується, вам буде надано значення, яке повертається, викликаючи посилання на функцію, передану на module.factory .
Синтаксис: module.provider( 'providerName', function );
Результат: При оголошенні providerName як аргументу, що ін'єктується, вам буде надано (new ProviderFunction()).$get()
. Функція конструктора ProviderFunction
ініціюється до виклику методу $ get - це посилання на функцію, передане module.provider.
Переваги постачальників мають те, що вони можуть бути налаштовані під час фази налаштування модуля.
Дивіться тут за наданий код.
Ось чудове подальше пояснення Місько:
provide.value('a', 123);
function Controller(a) {
expect(a).toEqual(123);
}
У цьому випадку інжектор просто повертає значення як є. Але що робити, якщо ви хочете обчислити значення? Потім використовуйте фабрику
provide.factory('b', function(a) {
return a*2;
});
function Controller(b) {
expect(b).toEqual(246);
}
Так factory
це функція, яка відповідає за створення значення. Зауважте, що фабрична функція може вимагати інших залежностей.
Але що робити, якщо ви хочете бути більш OO та мати клас під назвою Greeter?
function Greeter(a) {
this.greet = function() {
return 'Hello ' + a;
}
}
Тоді для інстанції вам доведеться писати
provide.factory('greeter', function(a) {
return new Greeter(a);
});
Тоді ми могли б попросити "привітатись" у контролері, як це
function Controller(greeter) {
expect(greeter instanceof Greeter).toBe(true);
expect(greeter.greet()).toEqual('Hello 123');
}
Але це занадто багатослівно. Коротший спосіб написати це було бprovider.service('greeter', Greeter);
Але що робити, якщо ми хотіли налаштувати Greeter
клас перед ін'єкцією? Тоді ми могли б написати
provide.provider('greeter2', function() {
var salutation = 'Hello';
this.setSalutation = function(s) {
salutation = s;
}
function Greeter(a) {
this.greet = function() {
return salutation + ' ' + a;
}
}
this.$get = function(a) {
return new Greeter(a);
};
});
Тоді ми можемо це зробити:
angular.module('abc', []).config(function(greeter2Provider) {
greeter2Provider.setSalutation('Halo');
});
function Controller(greeter2) {
expect(greeter2.greet()).toEqual('Halo 123');
}
В якості примітки, service
, factory
, і value
все отримані від постачальника.
provider.service = function(name, Class) {
provider.provide(name, function() {
this.$get = function($injector) {
return $injector.instantiate(Class);
};
});
}
provider.factory = function(name, factory) {
provider.provide(name, function() {
this.$get = function($injector) {
return $injector.invoke(factory);
};
});
}
provider.value = function(name, value) {
provider.factory(name, function() {
return value;
});
};
toEqual
і greeter.Greet
є. Чому б не використати щось трохи більш реальне і відносне?
factory
/ service
/ provider
:var myApp = angular.module('myApp', []);
//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!";
};
});
//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
return {
sayHello: function() {
return "Hello, World!";
}
};
});
//provider style, full blown, configurable version
myApp.provider('helloWorld', function() {
this.name = 'Default';
this.$get = function() {
var name = this.name;
return {
sayHello: function() {
return "Hello, " + name + "!";
}
}
};
this.setName = function(name) {
this.name = name;
};
});
//hey, we can configure a provider!
myApp.config(function(helloWorldProvider){
helloWorldProvider.setName('World');
});
function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
$scope.hellos = [
helloWorld.sayHello(),
helloWorldFromFactory.sayHello(),
helloWorldFromService.sayHello()];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
{{hellos}}
</div>
</body>
this
змінюється контекст у $get
функції? - ви більше не посилаєтесь на спеціалізованого постачальника в цій функції.
this
фактично не змінює контекст, тому що те, що викликається, є new Provider()
$ get (), куди Provider
передається функція app.provider
. Тобто, що $get()
викликається як метод на побудованому Provider
, так this
буде посилатися на Provider
приклад, який пропонує.
Unknown provider: helloWorldProvider <- helloWorld
коли це працює локально? Коментуючи це, така ж помилка для інших 2-х прикладів. Чи є якась прихована конфігурація провайдера? (Angular 1.0.8) - Знайдено: stackoverflow.com/questions/12339272/…
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) Коли ви користуєтесь Сервісом , AngularJS інстанціює його за кадром за допомогою "нового" ключового слова. Через це ви додасте властивості до "цього", і служба поверне "це". Коли ви передасте послугу в свій контролер, ці властивості на "це" тепер будуть доступні на цьому контролері через вашу службу.
app.controller(‘myServiceCtrl’, function($scope, myService){
$scope.artist = myService.getArtist();
});
app.service(‘myService’, function(){
var _artist = ‘Nelly’;
this.getArtist = function(){
return _artist;
}
});
3) Постачальники - це єдина послуга, яку ви можете передати у свою функцію .config (). Використовуйте постачальника, коли ви хочете надати конфігурацію для вашого об’єкта послуги перед модулем, перш ніж зробити його доступним.
app.controller(‘myProvider’, function($scope, myProvider){
$scope.artist = myProvider.getArtist();
$scope.data.thingFromConfig = myProvider.thingOnConfig;
});
app.provider(‘myProvider’, function(){
//Only the next two lines are available in the app.config()
this._artist = ‘’;
this.thingFromConfig = ‘’;
this.$get = function(){
var that = this;
return {
getArtist: function(){
return that._artist;
},
thingOnConfig: that.thingFromConfig
}
}
});
app.config(function(myProviderProvider){
myProviderProvider.thingFromConfig = ‘This was set in config’;
});
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;
});
Тут ви помітите, що ми не прив'язуємо ці змінні / функції до "служби". Ми просто створюємо їх для того, щоб пізніше їх використовувати чи змінювати.
Тепер, коли наші помічникові / приватні змінні та функціонують на місці, давайте додамо деякі властивості до об’єкта 'service'. Що б ми не поставили на "послугу", можна безпосередньо використовувати всередині того контролера, в який ми передаємо "myFactory".
Ми створимо методи setArtist і getArtist, які просто повертають або встановлюють виконавця. Ми також створимо метод, який викликатиме API iTunes за допомогою створеної нами URL-адреси. Цей метод поверне обіцянку, яка виконається, коли дані повернуться з iTunes API. Якщо ви не мали великого досвіду використання обіцянок в AngularJS, я настійно рекомендую зробити глибокий занурення у них.
Нижче 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 below line creates an object(obj) 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, створення служби в AngularJS має бути простішим для розуміння.
Найголовніше, що потрібно розуміти під час створення Служби - це знати, що Служби створені за допомогою "нового" ключового слова. Поєднуючи ці знання з нашими прикладами вище, тепер ви повинні визнати, що ви будете прив’язувати свої властивості та методи безпосередньо до "цього", який потім буде повернуто з самої Служби. Давайте розглянемо це в дії.
На відміну від того, що ми робили з фабричного прикладу, нам не потрібно створювати об'єкт, а потім повертати цей об'єкт, тому що, як уже згадувалося багато разів, ми використовували ключове слово "новий", щоб інтерпретатор створив цей об'єкт, чи його делегувати це прототип, то поверніть його нам, не маючи необхідності виконувати роботу.
Спочатку спочатку давайте створимо нашу "приватну" та допоміжну функцію. Це повинно виглядати дуже знайомо, оскільки ми зробили абсолютно те ж саме з нашою фабрикою. Я не поясню, що тут робить кожен рядок, тому що я це робив на заводському прикладі, якщо ви плутаєте, перечитайте заводський приклад.
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);
})
}
});
Як я вже згадував раніше, коли ви дійсно зрозумієте, що означає "нове", Послуги майже ідентичні фабрикам в AngularJS.
3) Постачальник
Найбільше, що потрібно пам’ятати про Провайдерів, - це те, що вони є єдиною послугою, яку можна передати у додаток app.config своєї програми. Це має величезне значення, якщо вам потрібно змінити частину об’єкта обслуговування, перш ніж він буде доступний скрізь у вашій програмі. Хоча вони дуже схожі на Послуги / Фабрики, є кілька відмінностей, про які ми поговоримо.
Спочатку ми створили свого Постачальника аналогічним чином, як ми це зробили з нашим Сервісом та Заводом. Нижчі змінні - це наша "приватна" та допоміжна функція.
app.provider('myProvider', function(){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
//Going to set this property on the config function below.
this.thingFromConfig = ‘’;
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
}
* Знову, якщо якась частина вищевказаного коду є заплутаною, перегляньте розділ «Фабрика», де я пояснюю, що це все робить для більш детальної інформації.
Ви можете подумати про Провайдерів як про три розділи. Перший розділ - це "приватні" змінні / функції, які будуть змінені / встановлені пізніше (показано вище). Другий розділ - це змінні / функції, які будуть доступні у вашій функції app.config, і тому вони доступні для зміни, перш ніж вони будуть доступні деінде (також показано вище). Важливо зауважити, що ці змінні потрібно додавати до ключового слова "це". У нашому прикладі для зміни в програмі app.config буде доступна лише "thingFromConfig". Третій розділ (показаний нижче) - це всі змінні / функції, які будуть доступні у вашому контролері, коли ви переходите в службу 'myProvider' у цей конкретний контролер.
Під час створення послуги з Постачальником єдиними властивостями / методами, які будуть доступні у вашому контролері, є ті властивості / методи, які повертаються з функції $ get (). Нижче наведений код ставить $ get на "this" (що, як ми знаємо, згодом буде повернуто з цієї функції). Тепер ця функція $ get повертає всі методи / властивості, які ми хочемо бути доступними в контролері. Ось приклад коду.
this.$get = function($http, $q){
return {
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: function(artist){
_artist = artist;
},
getArtist: function(){
return _artist;
},
thingOnConfig: this.thingFromConfig
}
}
Тепер повний код Постачальника виглядає приблизно так
app.provider('myProvider', function(){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
//Going to set this property on the config function below
this.thingFromConfig = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
this.$get = function($http, $q){
return {
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: function(artist){
_artist = artist;
},
getArtist: function(){
return _artist;
},
thingOnConfig: this.thingFromConfig
}
}
});
Тепер, як на нашому заводі, і сервіс, setArtist, getArtist і callItunes будуть доступні в тому контролері, в який ми передамо myProvider. Ось контролер myProvider (який майже точно такий, як наш заводський / сервісний контролер).
app.controller('myProviderCtrl', function($scope, myProvider){
$scope.data = {};
$scope.updateArtist = function(){
myProvider.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myProvider.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
$scope.data.thingFromConfig = myProvider.thingOnConfig;
});
Як уже згадувалося раніше, вся суть створення служби з Провайдером полягає в тому, щоб мати можливість змінювати деякі змінні за допомогою функції app.config до того, як кінцевий об’єкт буде переданий решті програми. Давайте подивимось приклад цього.
app.config(function(myProviderProvider){
//Providers are the only service you can pass into app.config
myProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works';
});
Тепер ви можете бачити, як "thingFromConfig" є таким же порожнім рядком у нашого постачальника, але коли це з'явиться в DOM, це буде "Це речення було встановлено ...".
Усі Послуги є одиночними ; вони отримують екземпляр один раз за додаток. Вони можуть бути будь-якого типу , будь то примітивні, об'єктні літерали, функції або навіть екземпляр користувацького типу.
value
, factory
, service
, constant
, І provider
методи все провайдери. Вони навчають інжектора як створювати послуги.
Найбільш багатослівний, але і найбільш повний - це рецепт постачальника. В інших чотирьох типів рецептів - Value, фабрика, Обслуговування і Constant - це просто синтаксичний цукор поверх рецепта постачальника .
Ви повинні використовувати Рецепт Постачальника лише тоді, коли Ви хочете розкрити API для конфігурації для додатків, яку необхідно зробити перед запуском програми. Зазвичай це цікаво лише для послуг багаторазового використання, поведінка яких може знадобитися дещо відрізнятися між програмами.
decorator
.Розуміння заводу, сервісу та постачальника AngularJS
Усі вони використовуються для обміну одноразовими об'єктами, що використовуються повторно. Це допомагає ділитися кодом для багаторазового використання у вашому додатку / різних компонентах / модулях.
Від служби / фабрики Документів :
- Ліниво створений - Angular створює сервіс / завод лише тоді, коли компонент програми залежить від нього.
- Singletons - кожен компонент, що залежить від послуги, отримує посилання на один екземпляр, створений фабрикою послуг.
Фабрика - це функція, де ви можете маніпулювати / додавати логіку перед створенням об'єкта, тоді новостворений об’єкт повертається.
app.factory('MyFactory', function() {
var serviceObj = {};
//creating an object with methods/functions or variables
serviceObj.myFunction = function() {
//TO DO:
};
//return that object
return serviceObj;
});
Використання
Це може бути просто набір функцій, як клас. Отже, він може бути ініційований у різних контролерах, коли ви вводить його всередині функцій контролера / фабрики / директиви. Це створено лише один раз за додаток.
Просто переглядаючи служби, подумайте про прототип масиву. Служба - це функція, яка створює новий об'єкт за допомогою ключового слова "new". Ви можете додати властивості та функції до об’єкта служби за допомогою this
ключового слова. На відміну від заводу, він нічого не повертає (він повертає об'єкт, який містить методи / властивості).
app.service('MyService', function() {
//directly binding events to this context
this.myServiceFunction = function() {
//TO DO:
};
});
Використання
Використовуйте його, коли вам потрібно поділитися одним об’єктом у всій програмі. Наприклад, автентифіковані деталі користувачів, методи / дані, що надаються спільним доступом, функції утиліти тощо.
Для створення настроюваного об’єкта послуги використовується постачальник. Ви можете налаштувати сервісне налаштування з функції конфігурації. Він повертає значення за допомогою $get()
функції. $get
Функція запускається на виконання на етапі виконання в кутовий.
app.provider('configurableService', function() {
var name = '';
//this method can be be available at configuration time inside app.config.
this.setName = function(newName) {
name = newName;
};
this.$get = function() {
var getName = function() {
return name;
};
return {
getName: getName //exposed object to where it gets injected.
};
};
});
Використання
Коли вам потрібно надати модульну конфігурацію для вашого сервісного об'єкта, перш ніж зробити його доступним, наприклад. припустимо, ви хочете встановити URL-адресу API на основі середовища, наприклад dev
, stage
абоprod
ПРИМІТКА
Тільки постачальник буде доступний у фазі конфігурації кутових, а сервіс та фабрика - ні.
Сподіваємось, це прояснило ваше розуміння щодо фабрики, служби та постачальника .
only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications
, тому це не здається можливим, правда?
Для мене відкриття прийшло, коли я зрозумів, що всі вони працюють однаково: запустивши щось один раз , зберігаючи отримане значення, а потім кашлюю те саме збережене значення при посиланні через введення залежності .
Скажіть, у нас є:
app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);
Різниця між трьома полягає в тому, що:
a
Збережене значення надходить від запуску fn
.b
Збережене значення походить від new
ing fn
.c
Збережене значення походить від спочатку отримання екземпляра new
ing fn
, а потім запуску $get
методу цього примірника.Це означає, що в AngularJS є щось на зразок об’єкта кешу, значення кожного введення якого призначається лише один раз, коли вони були введені вперше, і де:
cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()
Ось чому ми використовуємо this
в сервісах і визначаємо this.$get
провайдери.
factory
. Єдина причина service
існування таких мов, як CoffeeScript, TypeScript, ES6 тощо, тому ви можете використовувати їх синтаксис класу. Ви потрібні provider
лише в тому випадку, якщо ваш модуль використовується в декількох програмах з різними налаштуваннями app.config()
. Якщо ваша послуга є чистим синглом або здатна створювати екземпляри чогось, залежить тільки від вашої реалізації.
Постачальник послуг проти постачальника:
Я намагаюся зробити це просто. Вся справа в базовій концепції JavaScript.
Перш за все, поговоримо про послуги в AngularJS!
Що таке сервіс: в AngularJS, сервісце не що інше, як однотонний JavaScript-об'єкт, який може зберігати корисні методи чи властивості. Цей одиночний об'єкт створений за принципом ngApp (Angular app) і його поділяють між усіма контролерами в поточному додатку. Коли Angularjs створює об'єкт сервісного обслуговування, він реєструє цей сервіс-об’єкт з унікальним іменем служби. Тому щоразу, коли нам потрібен екземпляр служби, Angular шукає в реєстрі це ім’я служби, і він повертає посилання на об’єкт служби. Такий, що ми можемо викликати метод, доступ до властивостей тощо на об’єкті обслуговування. У вас може виникнути питання, чи можете ви також розміщувати властивості та методи на об'єкті контролерів! То навіщо вам потрібен об’єкт обслуговування? Відповіді: послуги поділяються між кількома сферами контролера. Якщо ви помістите деякі властивості / методи в об’єкт області контролера, він буде доступний лише для поточного обсягу.
Отже, якщо є три сфери контролера, нехай це буде controllerA, controllerB і controllerC, всі будуть використовувати один екземпляр служби.
<div ng-controller='controllerA'>
<!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
<!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
<!-- controllerC scope -->
</div>
Як створити послугу?
AngularJS надають різні методи реєстрації послуги. Тут ми зосередимось на трьох методах завод (..), сервіс (..), постачальник (..);
Використовуйте це посилання для посилання на код
Ми можемо визначити заводську функцію, як показано нижче.
factory('serviceName',function fnFactory(){ return serviceInstance;})
AngularJS забезпечує метод 'factory (' serviceName ', fnFactory)', який бере два параметри, serviceName та функцію JavaScript. Angular створює екземпляр служби за допомогою виклику функції fnFactory () , наведеної нижче.
var serviceInstace = fnFactory();
Функція, що передається, може визначити об'єкт і повернути його. AngularJS просто зберігає цей об'єкт посилання на змінну, яка передається як перший аргумент. Все, що повернуто з fnFactory, буде прив'язане до службиInstance. Замість повернення об'єкта ми також можемо повернути функцію, значення тощо. Що б ми не повернули, вони будуть доступні для сервісного екземпляра.
Приклад:
var app= angular.module('myApp', []);
//creating service using factory method
app.factory('factoryPattern',function(){
var data={
'firstName':'Tom',
'lastName':' Cruise',
greet: function(){
console.log('hello!' + this.firstName + this.lastName);
}
};
//Now all the properties and methods of data object will be available in our service object
return data;
});
service('serviceName',function fnServiceConstructor(){})
Це інший спосіб, ми можемо зареєструвати послугу. Єдина відмінність полягає у тому, як AngularJS намагається створити об'єкт обслуговування. Цього разу кутовий використовує ключове слово "new" і викликає функцію конструктора щось на зразок нижче.
var serviceInstance = new fnServiceConstructor();
У функції конструктора ми можемо використовувати ключове слово "це" для додавання властивостей / методів до об'єкта обслуговування. приклад:
//Creating a service using the service method
var app= angular.module('myApp', []);
app.service('servicePattern',function(){
this.firstName ='James';
this.lastName =' Bond';
this.greet = function(){
console.log('My Name is '+ this.firstName + this.lastName);
};
});
Інший спосіб створення послуг - функція Provider (). Давайте нам цікаво створити сервіс, який просто відображає користувачеві якесь привітання. Але ми також хочемо забезпечити функціональність, щоб користувач міг встановити власне привітання. У технічному плані ми хочемо створити сервіси, що настроюються. Як ми можемо це зробити? Має бути спосіб, щоб програма могла передавати свої власні привітання, а Angularjs зробить це доступним для фабрики / функції конструктора, які створюють наш екземпляр служб. У такому випадку функція провайдера () виконує роботу. За допомогою функції провайдера () ми можемо створити сервіси, що настроюються.
Ми можемо створити налаштовані сервіси за допомогою синтаксису постачальника, як зазначено нижче
/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});
/*step2:configure the service */
app.config(function configureService(serviceProvider){});
1.Продуктор об'єкта створюється за допомогою функції конструктора, яку ми визначили у функції нашого провайдера.
var serviceProvider = new serviceProviderConstructor();
2. Функція, яку ми передали в app.config (), виконайте виконання. Це називається налаштування фази, і тут ми маємо шанс налаштувати наш сервіс.
configureService(serviceProvider);
3.Насправді екземпляр служби створюється за допомогою виклику $ get методу serviceProvider.
serviceInstance = serviceProvider.$get()
var app= angular.module('myApp', []);
app.provider('providerPattern',function providerConstructor(){
//this function works as constructor function for provider
this.firstName = 'Arnold ';
this.lastName = ' Schwarzenegger' ;
this.greetMessage = ' Welcome, This is default Greeting Message' ;
//adding some method which we can call in app.config() function
this.setGreetMsg = function(msg){
if(msg){
this.greetMessage = msg ;
}
};
//We can also add a method which can change firstName and lastName
this.$get = function(){
var firstName = this.firstName;
var lastName = this.lastName ;
var greetMessage = this.greetMessage;
var data={
greet: function(){
console.log('hello, ' + firstName + lastName+'! '+ greetMessage);
}
};
return data ;
};
});
app.config(
function(providerPatternProvider){
providerPatternProvider.setGreetMsg(' How do you do ?');
}
);
Підсумок:
Фабрика використовує функцію заводу, яка повертає службовий екземпляр. serviceInstance = fnFactory ();
Сервіс використовує функцію конструктора і Кутовий виклик цієї функції конструктора, використовуючи ключове слово 'new' для створення екземпляра служби. serviceInstance = новий fnServiceConstructor ();
Провайдер визначає функцію провайдера Конструктор, ця функція провайдераКонструктор визначає заводську функцію $ get . Кутові дзвінки $ get () для створення об’єкта обслуговування. Синтаксис постачальника має додаткову перевагу в налаштуванні об’єкта обслуговування до його інстанції. serviceInstance = $ get ();
Як наголошують кілька людей, тут правильно фабрика, постачальник, послуга, а також цінність і постійність є версіями одного і того ж. Ви можете розчленувати більш загальне provider
на всі з них. Так:
Ось стаття, з якої складається це зображення:
Ви надаєте AngularJS функцію, AngularJS буде кешувати і вводити повернене значення, коли запит фабрики.
Приклад:
app.factory('factory', function() {
var name = '';
// Return value **is** the object that will be injected
return {
name: name;
}
})
Використання:
app.controller('ctrl', function($scope, factory) {
$scope.name = factory.name;
});
Ви надаєте AngularJS функцію, AngularJS зателефонує новій для інстанції. AngularJS створює той випадок, який буде кешований та введений під час запиту послуги. З новим для створення екземпляра послуги було використано , ключове слово це дійсне і посилається на екземпляр.
Приклад:
app.service('service', function() {
var name = '';
this.setName = function(newName) {
name = newName;
}
this.getName = function() {
return name;
}
});
Використання:
app.controller('ctrl', function($scope, service) {
$scope.name = service.getName();
});
Ви надаєте AngularJS функцію, і AngularJS викличе її $get
функцію. Це повернене значення з$get
функції, яке буде кешоване та введене, коли запитується послуга.
Провайдери дозволяють налаштувати провайдера перед тим, як AngularJS викликає$get
метод, щоб отримати ін'єкційний.
Приклад:
app.provider('provider', function() {
var name = '';
this.setName = function(newName) {
name = newName;
}
this.$get = function() {
return {
name: name
}
}
})
Використання (як ін'єкційний в контролері)
app.controller('ctrl', function($scope, provider) {
$scope.name = provider.name;
});
Використання (налаштування постачальника раніше $get
викликається для створення ін'єкційного)
app.config(function(providerProvider) {
providerProvider.setName('John');
});
Я помітив щось цікаве, граючи з провайдерами.
Видимість ін'єкційних препаратів для постачальників різна, ніж для служб та заводів. Якщо ви оголосите AngularJS "постійною" (наприклад, myApp.constant('a', 'Robert');
), ви можете ввести його в сервіси, фабрики та постачальники.
Але якщо ви оголосите AngularJS "значенням" (напр., myApp.value('b', {name: 'Jones'});
), Ви можете ввести його в сервіси та на фабрики, а НЕ у функцію створення постачальника. Однак ви можете ввести його у $get
функцію, яку ви визначите для свого постачальника. Про це йдеться в документації AngularJS, але це легко пропустити. Ви можете знайти його на сторінці% provide у розділах про значення та постійні методи.
<div ng-app="MyAppName">
<div ng-controller="MyCtrl">
<p>from Service: {{servGreet}}</p>
<p>from Provider: {{provGreet}}</p>
</div>
</div>
<script>
var myApp = angular.module('MyAppName', []);
myApp.constant('a', 'Robert');
myApp.value('b', {name: 'Jones'});
myApp.service('greetService', function(a,b) {
this.greeter = 'Hi there, ' + a + ' ' + b.name;
});
myApp.provider('greetProvider', function(a) {
this.firstName = a;
this.$get = function(b) {
this.lastName = b.name;
this.fullName = this.firstName + ' ' + this.lastName;
return this;
};
});
function MyCtrl($scope, greetService, greetProvider) {
$scope.servGreet = greetService.greeter;
$scope.provGreet = greetProvider.fullName;
}
</script>
Це дуже заплутана частина для новачків, і я намагався пояснити це простими словами
AngularJS Service: використовується для обміну корисними функціями з посиланням на службу в контролері. Послуга є однотонною, тому для однієї служби у браузері створюється лише один екземпляр, і однакова посилання використовується на всій сторінці.
У сервісі ми створюємо назви функцій як властивості з цим об’єктом.
AngularJS Factory: призначення Factory також те саме, що і Service, але в цьому випадку ми створюємо новий об'єкт і додаємо функції як властивості цього об'єкта, і в кінці повертаємо цей об'єкт.
Провайдер AngularJS: мета цього знову однакова, однак Провайдер дає висновок про функцію $ get.
Визначення та використання сервісу, фабрики та постачальника пояснюється на веб- сайті http://www.dotnetfunda.com/articles/show/3156/difference-bet between-angularjs-service-factory-and-provider
Для мене найкращий і найпростіший спосіб зрозуміти різницю:
var service, factory;
service = factory = function(injection) {}
Як AngularJS створює конкретні компоненти (спрощено):
// service
var angularService = new service(injection);
// factory
var angularFactory = factory(injection);
Отже, для служби те, що стає компонентом AngularJS, є об'єктним екземпляром класу, який представлений функцією декларування служби. Для фабрики це результат, повернутий із функції декларації заводу. Фабрика може поводитись так само, як і служба:
var factoryAsService = function(injection) {
return new function(injection) {
// Service content
}
}
Найпростіший спосіб мислення такий:
Приклад заводського класу наведено у коментарях, а також у різниці постачальників.
new MyService()
чи щось :)
Моє уточнення з цього приводу:
В основному всі згадані типи (сервіс, фабрика, постачальник тощо) просто створюють і налаштовують глобальні змінні (які, звичайно, глобальні для всієї програми), як і старомодні глобальні змінні.
Хоча глобальні змінні не рекомендуються, реальне використання цих глобальних змінних полягає у забезпеченні введення залежності , передаючи змінну відповідному контролеру.
Існує багато рівнів ускладнень при створенні значень для "глобальних змінних":
app.config
.
app.config
файл, і ця $ .get функція поводиться так само, як і заводська вище, оскільки його повернене значення використовується для ініціалізації "глобальних" змінних. Моє розуміння дуже просте нижче.
Фабрика: Ви просто створюєте об'єкт всередині фабрики і повертаєте його.
Сервіс:
У вас просто є стандартна функція, яка використовує це ключове слово для визначення функції.
Постачальник:
Є $get
визначений вами об’єкт, і він може бути використаний для отримання об'єкта, який повертає дані.
Резюме з кутових документів :
Найкращі відповіді від SO:
https://stackoverflow.com/a/26924234/165673 (<- ДОБРЕ)
https://stackoverflow.com/a/27263882/165673
https://stackoverflow.com/a/16566144/165673
Всі хороші відповіді вже. Я хотів би додати ще кілька балів на Сервіс та Завод . Поряд із різницею між сервісом / заводом. Також у вас можуть виникнути такі питання, як:
Почнемо з різниці між Сервісом та Заводом:
Обидва є одиночними : Кожен раз, коли кутовий виявить їх як залежність вперше, він створює єдиний екземпляр служби / фабрики. Після створення екземпляра той самий екземпляр використовується назавжди.
Може використовуватися для моделювання об'єкта з поведінкою : вони можуть мати методи, внутрішні змінні стану тощо. Хоча спосіб написання цього коду відрізнятиметься.
Послуги:
Сервіс - це функція конструктора, і Angular буде створювати його, викликаючи новий yourServiceName()
. Це означає пару речей.
this
.new yourServiceName(
), він отримаєthis
об’єкт із усіма властивостями, які ви наділили на нього.Приклад зразка:
angular.service('MyService', function() {
this.aServiceVariable = "Ved Prakash"
this.aServiceMethod = function() {
return //code
};
});
Коли Angular вводить цю
MyService
послугу в контролер, який залежить від неї, цей контролер отримає aMyService
яку він може викликати функції, наприклад, MyService.aServiceMethod ().
Будьте обережні this
:
Оскільки побудована служба є об'єктом, методи, що знаходяться всередині неї, можуть посилатися на це, коли вони викликаються:
angular.service('ScoreKeeper', function($http) {
this.score = 0;
this.getScore = function() {
return this.score;
};
this.setScore = function(newScore) {
this.score = newScore;
};
this.addOne = function() {
this.score++;
};
});
Ви можете спокуситися зателефонувати ScoreKeeper.setScore
в ланцюжку обіцянок, наприклад, якщо ви ініціалізували рахунок, захопивши його з сервера: $http.get('/score').then(ScoreKeeper.setScore).
Проблема в цьому полягає в тому ScoreKeeper.setScore
, що виклик буде this
пов'язаний з, null
і ви отримаєте помилки. Кращий спосіб був би $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))
. Незалежно від того, чи вирішили ви використовувати це у своїх методах обслуговування чи ні, будьте уважні, як ви їх називаєте.
Повернення значення зService
:
Через те, як працюють конструктори JavaScript, якщо ви повернете комплексне значення (i.e., an Object)
з constructor
функції, абонент отримає цей Об'єкт замість цього екземпляра.
Це означає , що ви можете в основному копіпаст приклад фабрики знизу, які замінять factory
з service
, і він буде працювати:
angular.service('MyService', function($http) {
var api = {};
api.aServiceMethod= function() {
return $http.get('/users');
};
return api;
});
Отже, коли Angular побудує вашу службу за допомогою нового MyService (), він отримає цей об’єкт api замість екземпляра MyService.
Це поведінка для будь-яких складних значень (об'єктів, функцій), але не для примітивних типів.
Заводи:
Фабрика - це звичайна стара функція, яка повертає значення. Повернене значення - це те, що вводиться в речі, які залежать від заводу. Типовий заводський візерунок у Angular полягає у поверненні об'єкта з функціями як властивості, наприклад:
angular.factory('MyFactory', function($http) {
var api = {};
api.aFactoryMethod= function() {
return $http.get('/users');
};
return api;
});
Введене значення для заводської залежності - це повернене значення заводу, і воно не повинно бути об'єктом. Це може бути функцією
Відповіді на вище 1 та 2 питання:
Здебільшого просто дотримуйтесь використання фабрик для всього. Їх поведінку легше зрозуміти. Немає вибору робити, повертати значення чи ні, і, крім того, помилок не буде введено, якщо ви зробите не так.
Я все ще називаю їх «послугами», коли говорю про введення їх як залежності.
Поведінка служби / заводу дуже схожа, і деякі люди скажуть, що будь-яка з них нормальна. Це дещо правда, але мені легше слідувати порадам керівництва зі стилю Джона Папи і просто дотримуватися фабрик. **
Додатковим уточненням є те, що фабрики можуть створювати функції / примітиви, тоді як служби не можуть. Перевірте цей jsFiddle на основі Epokk: http://jsfiddle.net/skeller88/PxdSP/1351/ .
Фабрика повертає функцію, яку можна викликати:
myApp.factory('helloWorldFromFactory', function() {
return function() {
return "Hello, World!";
};
});
Фабрика також може повернути об'єкт методом, до якого можна викликати:
myApp.factory('helloWorldFromFactory', function() {
return {
sayHello: function() {
return "Hello, World!";
}
};
});
Служба повертає об'єкт методом, до якого можна викликати:
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!";
};
});
Детальніше дивіться у публікації, яку я написав про різницю: http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/
Вже є хороші відповіді, але я просто хочу поділитися цим.
Перш за все: Провайдер - це спосіб / рецепт створення service
(одиночного об’єкта), який передбачає ввести $ injector (як AngulaJS іде про шаблон IoC).
І вартість, фабрика, обслуговування та постійна (4 способи) - синтаксичний цукор над Provider шлях / recepie.
Є Service vs Factory
частина була висвітлена:
https://www.youtube.com/watch?v=BLzNCkPn3ao
Служба - це new
фактично ключове слово, яке, як ми знаємо, робить 4 речі:
prototype
об’єктомcontext
доthis
this
І Factory - це Factory Pattern - містить функції, що повертають такі об'єкти, як ця Служба.
І це просте / коротке відео: охоплює також Постачальника : https://www.youtube.com/watch?v=HvTZbQ_hUZY (там ви можете побачити, як вони переходять від заводу до постачальника)
Рецепт постачальника використовується в основному в конфігурації програми, перш ніж програма повністю запуститься / ініціалізується.
Прочитавши всі ці публікації, це створило для мене більше плутанини .. Але все-таки все є повноцінною інформацією .. нарешті я знайшов наступну таблицю, яка дасть інформацію з простим порівнянням
І для початківців розуміють: - Це може бути неправильним випадком використання, але на високому рівні це те, що використовується для цих трьох.
angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})
Для основних сценаріїв завод та сервіс поводяться однаково.
Ось декілька кодів бройлерів, які я придумав як шаблон-код для фабрики об'єктів в AngularjS. Я використовував Автомобіль / CarFactory як приклад для ілюстрації. Створює простий код реалізації в контролері.
<script>
angular.module('app', [])
.factory('CarFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Car = function() {
// initialize instance properties
angular.extend(this, {
color : null,
numberOfDoors : null,
hasFancyRadio : null,
hasLeatherSeats : null
});
// generic setter (with optional default value)
this.set = function(key, value, defaultValue, allowUndefined) {
// by default,
if (typeof allowUndefined === 'undefined') {
// we don't allow setter to accept "undefined" as a value
allowUndefined = false;
}
// if we do not allow undefined values, and..
if (!allowUndefined) {
// if an undefined value was passed in
if (value === undefined) {
// and a default value was specified
if (defaultValue !== undefined) {
// use the specified default value
value = defaultValue;
} else {
// otherwise use the class.prototype.defaults value
value = this.defaults[key];
} // end if/else
} // end if
} // end if
// update
this[key] = value;
// return reference to this object (fluent)
return this;
}; // end this.set()
}; // end this.Car class definition
// instance properties default values
this.Car.prototype.defaults = {
color: 'yellow',
numberOfDoors: 2,
hasLeatherSeats: null,
hasFancyRadio: false
};
// instance factory method / constructor
this.Car.prototype.instance = function(params) {
return new
this.constructor()
.set('color', params.color)
.set('numberOfDoors', params.numberOfDoors)
.set('hasFancyRadio', params.hasFancyRadio)
.set('hasLeatherSeats', params.hasLeatherSeats)
;
};
return new this.Car();
}) // end Factory Definition
.controller('testCtrl', function($scope, CarFactory) {
window.testCtrl = $scope;
// first car, is red, uses class default for:
// numberOfDoors, and hasLeatherSeats
$scope.car1 = CarFactory
.instance({
color: 'red'
})
;
// second car, is blue, has 3 doors,
// uses class default for hasLeatherSeats
$scope.car2 = CarFactory
.instance({
color: 'blue',
numberOfDoors: 3
})
;
// third car, has 4 doors, uses class default for
// color and hasLeatherSeats
$scope.car3 = CarFactory
.instance({
numberOfDoors: 4
})
;
// sets an undefined variable for 'hasFancyRadio',
// explicitly defines "true" as default when value is undefined
$scope.hasFancyRadio = undefined;
$scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);
// fourth car, purple, 4 doors,
// uses class default for hasLeatherSeats
$scope.car4 = CarFactory
.instance({
color: 'purple',
numberOfDoors: 4
});
// and then explicitly sets hasLeatherSeats to undefined
$scope.hasLeatherSeats = undefined;
$scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);
// in console, type window.testCtrl to see the resulting objects
});
</script>
Ось простіший приклад. Я використовую декілька сторонніх бібліотек, які очікують, що об'єкт "Позиція" відкриває широту та довготу, але за допомогою різних властивостей об'єкта. Я не хотів зламати код постачальника, тому я відкоригував об'єкти "Позиція", якими я проходив.
angular.module('app')
.factory('PositionFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Position = function() {
// initialize instance properties
// (multiple properties to satisfy multiple external interface contracts)
angular.extend(this, {
lat : null,
lon : null,
latitude : null,
longitude : null,
coords: {
latitude: null,
longitude: null
}
});
this.setLatitude = function(latitude) {
this.latitude = latitude;
this.lat = latitude;
this.coords.latitude = latitude;
return this;
};
this.setLongitude = function(longitude) {
this.longitude = longitude;
this.lon = longitude;
this.coords.longitude = longitude;
return this;
};
}; // end class definition
// instance factory method / constructor
this.Position.prototype.instance = function(params) {
return new
this.constructor()
.setLatitude(params.latitude)
.setLongitude(params.longitude)
;
};
return new this.Position();
}) // end Factory Definition
.controller('testCtrl', function($scope, PositionFactory) {
$scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
$scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller
;
Використовуючи в якості довідки цю сторінку та документацію (яка, схоже, значно покращилася з моменту, коли я останній раз переглядала), я зібрав наступну реальну (-іш) світову демонстрацію, яка використовує 4 з 5 ароматів постачальника; Цінність, постійний, заводський і повний видувний постачальник.
HTML:
<div ng-controller="mainCtrl as main">
<h1>{{main.title}}*</h1>
<h2>{{main.strapline}}</h2>
<p>Earn {{main.earn}} per click</p>
<p>You've earned {{main.earned}} by clicking!</p>
<button ng-click="main.handleClick()">Click me to earn</button>
<small>* Not actual money</small>
</div>
додаток
var app = angular.module('angularProviders', []);
// A CONSTANT is not going to change
app.constant('range', 100);
// A VALUE could change, but probably / typically doesn't
app.value('title', 'Earn money by clicking');
app.value('strapline', 'Adventures in ng Providers');
// A simple FACTORY allows us to compute a value @ runtime.
// Furthermore, it can have other dependencies injected into it such
// as our range constant.
app.factory('random', function randomFactory(range) {
// Get a random number within the range defined in our CONSTANT
return Math.random() * range;
});
// A PROVIDER, must return a custom type which implements the functionality
// provided by our service (see what I did there?).
// Here we define the constructor for the custom type the PROVIDER below will
// instantiate and return.
var Money = function(locale) {
// Depending on locale string set during config phase, we'll
// use different symbols and positioning for any values we
// need to display as currency
this.settings = {
uk: {
front: true,
currency: '£',
thousand: ',',
decimal: '.'
},
eu: {
front: false,
currency: '€',
thousand: '.',
decimal: ','
}
};
this.locale = locale;
};
// Return a monetary value with currency symbol and placement, and decimal
// and thousand delimiters according to the locale set in the config phase.
Money.prototype.convertValue = function(value) {
var settings = this.settings[this.locale],
decimalIndex, converted;
converted = this.addThousandSeparator(value.toFixed(2), settings.thousand);
decimalIndex = converted.length - 3;
converted = converted.substr(0, decimalIndex) +
settings.decimal +
converted.substr(decimalIndex + 1);
converted = settings.front ?
settings.currency + converted :
converted + settings.currency;
return converted;
};
// Add supplied thousand separator to supplied value
Money.prototype.addThousandSeparator = function(value, symbol) {
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, symbol);
};
// PROVIDER is the core recipe type - VALUE, CONSTANT, SERVICE & FACTORY
// are all effectively syntactic sugar built on top of the PROVIDER construct
// One of the advantages of the PROVIDER is that we can configure it before the
// application starts (see config below).
app.provider('money', function MoneyProvider() {
var locale;
// Function called by the config to set up the provider
this.setLocale = function(value) {
locale = value;
};
// All providers need to implement a $get method which returns
// an instance of the custom class which constitutes the service
this.$get = function moneyFactory() {
return new Money(locale);
};
});
// We can configure a PROVIDER on application initialisation.
app.config(['moneyProvider', function(moneyProvider) {
moneyProvider.setLocale('uk');
//moneyProvider.setLocale('eu');
}]);
// The ubiquitous controller
app.controller('mainCtrl', function($scope, title, strapline, random, money) {
// Plain old VALUE(s)
this.title = title;
this.strapline = strapline;
this.count = 0;
// Compute values using our money provider
this.earn = money.convertValue(random); // random is computed @ runtime
this.earned = money.convertValue(0);
this.handleClick = function() {
this.count ++;
this.earned = money.convertValue(random * this.count);
};
});
Робоча демонстрація .
Ця відповідь стосується теми / питання
АБО
в основному те, що відбувається
Коли ви робите factory()
це, ви встановлюєте, що ви function
надали у другому аргументі постачальнику, $get
і повертаєте його ( provider(name, {$get:factoryFn })
), все, що ви отримуєте, provider
але немає іншого властивості / методу, крім$get
цього provider
(значить, ви не можете налаштувати це)
Вихідний код заводу
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
};
Здійснюючи service()
це, ви повертаєте фабрику () з function
ін'єкцією constructor
(повертайте екземпляр конструктора, який ви надали у вашій службі) і повертаєте його
Вихідний код послуги
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
};
Таким чином, в основному в обох випадках ви, зрештою, отримуєте провайдерів $ встановити свою функцію, яку ви надали, але ви можете дати що-небудь додатково, ніж $ get, як ви могли спочатку надати у постачальника () для конфігураційного блоку
Я знаю багато відмінних відповідей, але мені потрібно поділитися своїм досвідом використання
1. service
для більшості випадків за замовчуванням
2., які factory
використовуються для створення служби для конкретного примірника
// factory.js ////////////////////////////
(function() {
'use strict';
angular
.module('myApp.services')
.factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];
function xFactoryImp($http) {
var fac = function (params) {
this._params = params; // used for query params
};
fac.prototype.nextPage = function () {
var url = "/_prc";
$http.get(url, {params: this._params}).success(function(data){ ...
}
return fac;
}
})();
// service.js //////////////////////////
(function() {
'use strict';
angular
.module('myApp.services')
.service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];
function xServiceImp($http) {
this._params = {'model': 'account','mode': 'list'};
this.nextPage = function () {
var url = "/_prc";
$http.get(url, {params: this._params}).success(function(data){ ...
}
}
})();
та використовуючи:
controller: ['xFactory', 'xService', function(xFactory, xService){
// books = new instance of xFactory for query 'book' model
var books = new xFactory({'model': 'book', 'mode': 'list'});
// accounts = new instance of xFactory for query 'accounts' model
var accounts = new xFactory({'model': 'account', 'mode': 'list'});
// accounts2 = accounts variable
var accounts2 = xService;
...
Трохи запізнюємось на вечірку. Але я подумав, що це корисніше для тих, хто хотів би дізнатися (чи мати чіткість) щодо розробки користувальницьких служб Angular JS за допомогою заводських, службових та постачальницьких методологій.
Я натрапив на це відео, яке чітко пояснює фабричні, службові та провайдерські методології розробки користувальницьких послуг AngularJS:
https://www.youtube.com/watch?v=oUXku28ex-M
Вихідний код: http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service
Код, розміщений тут, скопіюється прямо з вищенаведеного джерела, щоб принести користь читачам.
Код для користувальницької служби на основі "фабрики" такий (що йде з версіями синхронізації та асинхронізації разом з викликом служби http):
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcFactory',
function($scope, calcFactory) {
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function() {
//$scope.sum = calcFactory.getSum($scope.a, $scope.b); //synchronous
calcFactory.getSum($scope.a, $scope.b, function(r) { //aynchronous
$scope.sum = r;
});
};
}
]);
app.factory('calcFactory', ['$http', '$log',
function($http, $log) {
$log.log("instantiating calcFactory..");
var oCalcService = {};
//oCalcService.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//oCalcService.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
oCalcService.getSum = function(a, b, cb) { //using http service
$http({
url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp) {
$log.log(resp.data);
cb(resp.data);
}, function(resp) {
$log.error("ERROR occurred");
});
};
return oCalcService;
}
]);
Код методології "служби" для користувацьких служб (це досить схоже на "заводський", але відрізняється від точки зору синтаксису):
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function(){
//$scope.sum = calcService.getSum($scope.a, $scope.b);
calcService.getSum($scope.a, $scope.b, function(r){
$scope.sum = r;
});
};
}]);
app.service('calcService', ['$http', '$log', function($http, $log){
$log.log("instantiating calcService..");
//this.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//this.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
this.getSum = function(a, b, cb){
$http({
url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp){
$log.log(resp.data);
cb(resp.data);
},function(resp){
$log.error("ERROR occurred");
});
};
}]);
Код методології "постачальника" для користувацьких послуг (це необхідно, якщо ви хочете розробити сервіс, який можна було б налаштувати):
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function(){
//$scope.sum = calcService.getSum($scope.a, $scope.b);
calcService.getSum($scope.a, $scope.b, function(r){
$scope.sum = r;
});
};
}]);
app.provider('calcService', function(){
var baseUrl = '';
this.config = function(url){
baseUrl = url;
};
this.$get = ['$log', '$http', function($log, $http){
$log.log("instantiating calcService...")
var oCalcService = {};
//oCalcService.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//oCalcService.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
oCalcService.getSum = function(a, b, cb){
$http({
url: baseUrl + '/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp){
$log.log(resp.data);
cb(resp.data);
},function(resp){
$log.error("ERROR occurred");
});
};
return oCalcService;
}];
});
app.config(['calcServiceProvider', function(calcServiceProvider){
calcServiceProvider.config("http://localhost:4467");
}]);
Нарешті, інтерфейс користувача, який працює з будь-яким із перерахованих вище служб:
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js" ></script>
<script type="text/javascript" src="t03.js"></script>
</head>
<body ng-app="app">
<div ng-controller="emp">
<div>
Value of a is {{a}},
but you can change
<input type=text ng-model="a" /> <br>
Value of b is {{b}},
but you can change
<input type=text ng-model="b" /> <br>
</div>
Sum = {{sum}}<br>
<button ng-click="doSum()">Calculate</button>
</div>
</body>
</html>
Для уточнення речей із джерела AngularJS ви бачите, що сервіс просто викликає заводську функцію, яка, в свою чергу, викликає функцію постачальника:
function factory(name, factoryFn) {
return provider(name, { $get: factoryFn });
}
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
Давайте обговоримо три способи керування бізнес-логікою в AngularJS простим способом: ( натхненний курсом Якокова Coursera AngularJS )
ОБСЛУГОВУВАННЯ :
Синтаксис:
app.js
var app = angular.module('ServiceExample',[]);
var serviceExampleController =
app.controller('ServiceExampleController', ServiceExampleController);
var serviceExample = app.service('NameOfTheService', NameOfTheService);
ServiceExampleController.$inject = ['NameOfTheService'] //protects from minification of js files
function ServiceExampleController(NameOfTheService){
serviceExampleController = this;
serviceExampleController.data = NameOfTheService.getSomeData();
}
function NameOfTheService(){
nameOfTheService = this;
nameOfTheService.data = "Some Data";
nameOfTheService.getSomeData = function(){
return nameOfTheService.data;
}
}
index.html
<div ng-controller = "ServiceExampleController as serviceExample">
{{serviceExample.data}}
</div>
Особливості обслуговування:
ЗАВОД
Спочатку давайте подивимось на синтаксис:
app.js :
var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);
//first implementation where it returns a function
function NameOfTheFactoryOne(){
var factory = function(){
return new SomeService();
}
return factory;
}
//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
var factory = {
getSomeService : function(){
return new SomeService();
}
};
return factory;
}
Тепер використовуємо зазначені вище в контролері:
var factoryOne = NameOfTheFactoryOne() //since it returns a function
factoryOne.someMethod();
var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
factoryTwo.someMethod();
Особливості заводу:
.service()
Метод є заводом , який завжди справляє один і той же тип сервісу, який одноелементен, і без якого - або простого способу налаштувати його поведінку. Цей .service()
метод зазвичай використовується як ярлик для чогось, що не вимагає жодної конфігурації.ПОСТАВНИК
Давайте ще раз спочатку розглянемо синтаксис:
angular.module('ProviderModule', [])
.controller('ProviderModuleController', ProviderModuleController)
.provider('ServiceProvider', ServiceProvider)
.config(Config); //optional
Config.$inject = ['ServiceProvider'];
function Config(ServiceProvider) {
ServiceProvider.defaults.maxItems = 10; //some default value
}
ProviderModuleController.$inject = ['ServiceProvider'];
function ProviderModuleController(ServiceProvider) {
//some methods
}
function ServiceProvider() {
var provider = this;
provider.defaults = {
maxItems: 10
};
provider.$get = function () {
var someList = new someListService(provider.defaults.maxItems);
return someList;
};
}
}
Особливості Постачальника:
.service
або .factory
.$get
функція, яка безпосередньо приєднана до екземпляра постачальника. Ця функція є заводською функцією. Іншими словами, це так само , як той , який ми використовуємо , щоб забезпечити до .factory
методу. У цій функції ми створюємо власну службу. Ця $get
властивість, яка є функцією, - це те, що робить провайдера постачальником . AngularJS розраховує, що постачальник має властивість $ get, значенням якої є функція, яку Angular буде розглядати як заводську функцію. Але те, що робить цілу настройку всього провайдера дуже особливою, це той факт, що ми можемо надати деякий config
об’єкт всередині постачальника послуг, і це, як правило, поставляється із за замовчуванням, яке ми можемо згодом перезаписати на етапі, де ми можемо налаштувати всю програму.Фабрика: Фабрика, на якій ви фактично створюєте об'єкт всередині фабрики та повертаєте його.
послуга: Служба, у якої ви просто маєте стандартну функцію, яка використовує це ключове слово для визначення функції.
провайдер: У постачальника є визначене вами $ get, яке може бути використане для отримання об'єкта, який повертає дані.
По суті, Постачальник, Фабрика та Сервіс - це всі Послуги. Фабрика - це особливий випадок Сервісу, коли все, що вам потрібно, - це функція $ get (), що дозволяє писати її з меншим кодом.
Основні відмінності між послугами, фабриками та постачальниками - їх складність. Послуги - це найпростіша форма, заводи трохи надійніші, а постачальники налаштовуються під час виконання.
Ось коротка інформація про те, коли користуватися кожним:
Фабрика : вартість, яку ви надаєте, повинна бути обчислена на основі інших даних.
Сервіс : Ви повертаєте об'єкт методами.
Постачальник : Ви хочете мати можливість налаштувати під час фази налаштування об'єкт, який буде створений перед його створенням. Використовуйте Постачальника переважно в конфігурації програми, перш ніж програма повністю ініціалізується.
1. Послуги - це одноосібні об'єкти, які створюються при необхідності і ніколи не очищаються до кінця життєвого циклу програми (коли браузер закритий). Контролери знищуються та очищаються, коли вони більше не потрібні.
2. Найпростіший спосіб створити послугу, використовуючи метод factory (). Фабричний () метод дозволяє нам визначити послугу, повернувши об’єкт, що містить сервісні функції та сервісні дані. Функція визначення послуги - це місце, де ми розміщуємо наші ін'єкційні послуги, такі як $ http та $ q. Наприклад:
angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
// our factory definition
user: {},
setName: function(newName) {
service.user['name'] = newName;
},
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });
Використання заводу () у нашому додатку
Використовувати фабрику у нашому додатку просто, оскільки ми можемо просто вводити її там, де нам це потрібно під час роботи.
angular.module('myApp')
.controller('MainController', function($scope, User) {
$scope.saveUser = User.save;
});
Синтаксичний цукор - це різниця . Потрібен лише провайдер. Або іншими словами, лише провайдер - це справжній кут, всі інші - отримані (щоб зменшити код). Існує також проста версія, що називається Value (), яка повертає просто значення, без обчислення або функції. Навіть цінність отримується від провайдера!
То чому такі ускладнення, чому ми не можемо просто скористатися провайдером і забути все інше? Він повинен допомогти нам легко писати код і краще спілкуватися. І чим жорсткішою буде відповідь, тим складнішою вона стане, тим краще продаватимуться рамки.
Кутова ін'єкція дає нам першу підказку для досягнення цього висновку.
"$ injector використовується для отримання екземплярів об'єктів, визначених постачальником ", не служба, не фабрика, а постачальник.
І кращою відповіддю буде така: "Кутовий сервіс створюється фабрикою послуг. Ці фабрики послуг - це функції, які, в свою чергу, створюються постачальником послуг. Постачальники послуг - це функції конструктора. При інстанції вони повинні містити властивість називається $ get, який утримує функцію фабрики послуг. "
Тож майстер-постачальник та інжектор і все стане на свої місця :). І в Typescript стає цікаво, коли $ get може бути реалізований у провайдера, успадкувавши від IServiceProvider.