อะไรคือความแตกต่างระหว่างService
, Provider
และFactory
ใน AngularJS?
service.factory
ของกรณีการใช้งานจากประสบการณ์ของผมสามารถจัดการได้ประสบความสำเร็จผ่านทาง ไม่ต้องการทำให้เรื่องนี้ซับซ้อนขึ้นอีก
อะไรคือความแตกต่างระหว่างService
, Provider
และFactory
ใน AngularJS?
service.factory
ของกรณีการใช้งานจากประสบการณ์ของผมสามารถจัดการได้ประสบความสำเร็จผ่านทาง ไม่ต้องการทำให้เรื่องนี้ซับซ้อนขึ้นอีก
คำตอบ:
จากรายชื่อผู้รับจดหมายของ AngularJS ฉันได้รับหัวข้อที่น่าทึ่งซึ่งอธิบายถึงการบริการ vs โรงงานและผู้ให้บริการและการใช้งานการฉีดของพวกเขา รวบรวมคำตอบ:
ไวยากรณ์: module.service( 'serviceName', function );
ผลลัพธ์: เมื่อประกาศ serviceName เป็นอาร์กิวเมนต์แบบฉีดคุณจะได้รับอินสแตนซ์ของฟังก์ชัน new FunctionYouPassedToService()
กล่าวอีกนัยหนึ่ง
ไวยากรณ์: module.factory( 'factoryName', function );
ผล: เมื่อประกาศ factoryName เป็นอาร์กิวเมนต์ฉีดที่คุณจะได้รับค่าที่ถูกส่งกลับโดยการเรียกใช้ฟังก์ชั่นการอ้างอิงที่ส่งผ่านไป module.factory
ไวยากรณ์: module.provider( 'providerName', function );
ผล: เมื่อประกาศ providername เป็นอาร์กิวเมนต์ฉีดที่คุณจะได้รับ (new ProviderFunction()).$get()
ฟังก์ชั่นคอนสตรัคได้รับการยกตัวอย่างก่อนที่วิธีการ $ get เรียกว่า - ProviderFunction
คือการอ้างอิงฟังก์ชั่นที่ส่งผ่านไปยัง module.provider
ผู้ให้บริการมีข้อได้เปรียบที่สามารถกำหนดค่าได้ในช่วงการกำหนดค่าโมดูล
ดูที่นี่สำหรับรหัสที่ให้
นี่คือคำอธิบายเพิ่มเติมที่ยอดเยี่ยมโดย Misko:
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()
. $ ได้รับ () ซึ่งเป็นฟังก์ชั่นที่ถูกส่งผ่านไปยังProvider
app.provider
กล่าว$get()
คือจะเรียกว่าเป็นวิธีการในการสร้างProvider
ดังนั้นthis
จะหมายถึงProvider
เป็นตัวอย่างที่แสดงให้เห็น
Unknown provider: helloWorldProvider <- helloWorld
เมื่อเรียกใช้ภายในเครื่อง แสดงความคิดเห็นข้อผิดพลาดเดียวกันสำหรับอีก 2 ตัวอย่าง มีการกำหนดค่าผู้ให้บริการที่ซ่อนอยู่บ้างไหม? (เชิงมุม 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 จะยกตัวอย่างทันทีโดยใช้คำหลัก 'ใหม่' ด้วยเหตุนี้คุณจะเพิ่มคุณสมบัติให้กับ '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;
}
});
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’;
});
ไม่ใช่ TL; DR
1) Factory Factory
เป็นวิธีที่นิยมที่สุดในการสร้างและกำหนดค่าบริการ ไม่มีอะไรมากไปกว่าสิ่งที่ TL; DR กล่าว คุณเพิ่งสร้างวัตถุเพิ่มคุณสมบัติเข้าไปแล้วส่งคืนวัตถุเดียวกันนั้น จากนั้นเมื่อคุณส่งโรงงานไปยังคอนโทรลเลอร์ของคุณคุณสมบัติเหล่านั้นบนวัตถุจะมีอยู่ในคอนโทรลเลอร์นั้นผ่านโรงงานของคุณ ตัวอย่างที่กว้างขวางยิ่งขึ้นอยู่ด้านล่าง
app.factory(‘myFactory’, function(){
var service = {};
return service;
});
ตอนนี้คุณสมบัติอะไรก็ตามที่เราแนบกับ 'บริการ' จะมีให้เราเมื่อเราส่ง 'myFactory' เข้าไปในตัวควบคุมของเรา
ตอนนี้เราจะเพิ่มตัวแปร 'ส่วนตัว' ลงในฟังก์ชันการโทรกลับของเรา สิ่งเหล่านี้จะไม่สามารถเข้าถึงได้โดยตรงจากคอนโทรลเลอร์ แต่ในที่สุดเราจะตั้งค่าเมธอด getter / setter ใน 'บริการ' เพื่อให้สามารถเปลี่ยนตัวแปร 'ส่วนตัว' เหล่านี้เมื่อจำเป็น
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;
});
ที่นี่คุณจะสังเกตเห็นว่าเราไม่ได้แนบตัวแปร / ฟังก์ชั่นเหล่านั้นเข้ากับ 'บริการ' เราแค่สร้างมันขึ้นมาเพื่อใช้หรือดัดแปลงในภายหลัง
ตอนนี้ผู้ช่วย / ตัวแปรส่วนตัวและฟังก์ชั่นของเราพร้อมใช้งานแล้วให้เพิ่มคุณสมบัติบางอย่างลงในออบเจ็กต์ 'บริการ' สิ่งที่เราใส่ใน 'บริการ' สามารถนำมาใช้โดยตรงภายในตัวควบคุมใดก็ตามที่เราผ่าน 'myFactory' เข้าไป
เราจะสร้างเมธอด setArtist และ getArtist ที่เพียงแค่คืนค่าหรือตั้งค่าศิลปิน เรากำลังจะสร้างวิธีการที่จะเรียก iTunes API ด้วย URL ที่สร้างขึ้นของเรา วิธีนี้จะคืนสัญญาที่จะตอบสนองเมื่อข้อมูลได้กลับมาจาก iTunes API หากคุณไม่เคยมีประสบการณ์การใช้คำสัญญาใน AngularJS มากนักฉันขอแนะนำให้ดำน้ำลึก
ด้านล่างsetArtistยอมรับศิลปินและอนุญาตให้คุณตั้งค่าศิลปิน getArtistส่งคืนศิลปิน callItunesสายแรก makeUrl () เพื่อสร้าง URL ที่เราจะใช้กับคำขอ $ http ของเรา จากนั้นจะตั้งค่าวัตถุสัญญาทำให้คำขอ $ http เป็น URL สุดท้ายของเราจากนั้นเนื่องจาก $ http ส่งคืนสัญญาเราจึงสามารถโทรหา. สำเร็จหรือ .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) บริการ
บางทีสิ่งที่สำคัญที่สุดที่ควรทราบเมื่อต้องจัดการกับการสร้างบริการคือการสร้างอินสแตนซ์ด้วยคำหลัก 'ใหม่' สำหรับคุณ gurus JavaScript คุณควรให้คำแนะนำอย่างละเอียดเกี่ยวกับลักษณะของรหัส สำหรับผู้ที่มีพื้นหลังที่ จำกัด ใน JavaScript หรือสำหรับผู้ที่ไม่คุ้นเคยกับสิ่งที่คำหลัก 'ใหม่' จริงลองมาตรวจทานพื้นฐาน JavaScript ที่จะช่วยเราในการทำความเข้าใจลักษณะของบริการ
หากต้องการดูการเปลี่ยนแปลงที่เกิดขึ้นเมื่อคุณเรียกใช้ฟังก์ชันด้วยคำหลัก 'ใหม่' ให้สร้างฟังก์ชันและเรียกใช้ด้วยคำหลัก 'ใหม่' จากนั้นให้แสดงสิ่งที่ล่ามทำเมื่อเห็นคำหลัก 'ใหม่' ผลลัพธ์ที่ได้จะเหมือนกันทั้งคู่
ก่อนอื่นมาสร้างตัวสร้างของเรา
var Person = function(name, age){
this.name = name;
this.age = age;
}
นี่คือฟังก์ชันตัวสร้าง JavaScript ทั่วไป ตอนนี้เมื่อใดก็ตามที่เราเรียกใช้ฟังก์ชั่นบุคคลโดยใช้คำหลัก 'ใหม่' นี้จะถูกผูกไว้กับวัตถุที่สร้างขึ้นใหม่
ตอนนี้เราจะเพิ่มวิธีการลงบนต้นแบบของบุคคลของเราเพื่อให้สามารถใช้ได้กับทุก ๆ ตัวอย่างของ 'ชั้นเรียน' ของบุคคล
Person.prototype.sayName = function(){
alert(‘My name is ‘ + this.name);
}
ตอนนี้เนื่องจากเราใส่ฟังก์ชั่น sayName ลงบนต้นแบบทุกอินสแตนซ์ของ Person จะสามารถเรียกใช้ฟังก์ชัน sayName เพื่อแจ้งเตือนการสั่งซื้อชื่อของอินสแตนซ์นั้น
ตอนนี้เรามีฟังก์ชั่นตัวสร้างบุคคลของเราและฟังก์ชั่น sayName ของเราบนต้นแบบแล้วลองสร้างตัวอย่างของบุคคลจากนั้นเรียกใช้ฟังก์ชั่น sayName
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’
ดังนั้นทุกรหัสเข้าด้วยกันสำหรับการสร้างตัวสร้างบุคคลเพิ่มฟังก์ชั่นของมันเป็นต้นแบบสร้างอินสแตนซ์ของบุคคลแล้วเรียกฟังก์ชั่นบนต้นแบบของมันมีลักษณะเช่นนี้
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 สิ่งแรกที่คุณควรสังเกตคือหลังจากใช้ 'ใหม่' ในตัวอย่างของเราเราสามารถเรียกเมธอด (sayName) บน 'tyler' เหมือนกับว่ามันเป็นวัตถุ - นั่นเป็นเพราะมันเป็น ดังนั้นก่อนอื่นเรารู้ว่าตัวสร้างบุคคลของเราส่งคืนวัตถุไม่ว่าเราจะเห็นว่าในโค้ดหรือไม่ ประการที่สองเรารู้ว่าเนื่องจากฟังก์ชั่น 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.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 ของคุณและพร้อมที่จะแก้ไขก่อนที่จะสามารถใช้งานได้ทุกที่ สิ่งสำคัญคือต้องทราบว่าต้องแนบตัวแปรเหล่านั้นกับคำหลัก 'this' ในตัวอย่างของเรามีเพียง 'thingFromConfig' เท่านั้นที่จะสามารถแก้ไขได้ใน app.config ส่วนที่สาม (แสดงด้านล่าง) คือตัวแปร / ฟังก์ชั่นทั้งหมดที่จะมีอยู่ในคอนโทรลเลอร์ของคุณเมื่อคุณส่งผ่านบริการ 'myProvider' ลงในคอนโทรลเลอร์เฉพาะนั้น
เมื่อสร้างบริการกับผู้ให้บริการคุณสมบัติ / วิธีการเดียวที่จะมีในตัวควบคุมของคุณคือคุณสมบัติ / วิธีการเหล่านั้นซึ่งส่งคืนจากฟังก์ชัน $ get () รหัสด้านล่างทำให้ $ รับ 'นี้' (ซึ่งเรารู้ว่าในที่สุดจะถูกส่งกลับจากฟังก์ชั่นนั้น) ตอนนี้ฟังก์ชั่น $ 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 จะเป็น 'ประโยคนี้ถูกตั้งค่า ... '
บริการทั้งหมดอยู่singletons ; พวกเขาจะได้รับอินสแตนซ์หนึ่งครั้งต่อแอป พวกเขาสามารถเป็นประเภทใด ๆไม่ว่าจะเป็นดั้งเดิมวัตถุตัวอักษรฟังก์ชั่นหรือแม้กระทั่งตัวอย่างของประเภทที่กำหนดเอง
value
, factory
, service
, constant
และprovider
วิธีการเป็นผู้ให้บริการทั้งหมด พวกเขาสอน Injector ถึงวิธีการยกตัวอย่างบริการ
verbose ที่สุด แต่ยังครอบคลุมมากที่สุดคือสูตรผู้ให้บริการ เหลืออีกสี่ประเภทสูตร - ราคา, โรงงาน, บริการและคงที่ - เป็นเพียงน้ำตาลประโยคด้านบนของสูตรผู้ให้บริการ
คุณควรใช้สูตรผู้ให้บริการเฉพาะเมื่อคุณต้องการเปิดเผย API สำหรับการกำหนดค่าทั่วทั้งแอปพลิเคชันที่ต้องทำก่อนที่แอปพลิเคชันจะเริ่มต้น นี่เป็นเรื่องที่น่าสนใจสำหรับบริการที่สามารถนำกลับมาใช้ใหม่ได้ซึ่งพฤติกรรมอาจต้องแตกต่างกันเล็กน้อยระหว่างแอปพลิเคชัน
decorator
ซึ่งแตกต่างจากค่าที่พวกเขาไม่สามารถที่จะตกแต่งโดยใช้ทำความเข้าใจกับโรงงาน AngularJS การบริการและผู้ให้บริการ
ทั้งหมดนี้ใช้เพื่อแชร์วัตถุซิงเกิลตันที่สามารถใช้ซ้ำได้ ช่วยในการแบ่งปันรหัสที่ใช้ซ้ำได้ในแอพของคุณ / ส่วนประกอบ / โมดูลต่างๆ
- Lazily instantiated - 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;
});
การใช้
มันอาจเป็นเพียงชุดของฟังก์ชั่นเช่นคลาส ดังนั้นมันสามารถสร้างอินสแตนซ์ในตัวควบคุมที่แตกต่างกันเมื่อคุณฉีดเข้าไปในฟังก์ชั่นคอนโทรลเลอร์ / โรงงาน / คำสั่งของคุณ มันเป็นอินสแตนซ์เพียงครั้งเดียวต่อแอป
เพียงแค่มองไปที่บริการต่างๆให้นึกถึงอาเรย์ต้นแบบ บริการคือฟังก์ชั่นที่ทำให้วัตถุใหม่โดยใช้คำสำคัญ 'ใหม่' คุณสามารถเพิ่มคุณสมบัติและฟังก์ชั่นให้กับวัตถุบริการโดยใช้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
ค่า 's fn
เก็บไว้มาจากการทำงานb
ค่า 's เก็บไว้มาจากไอเอ็นจีnew
fn
c
ค่า 's เก็บไว้มาจากครั้งแรกที่ได้รับตัวอย่างจากnew
ไอเอ็นจี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 (แอพเชิงมุม) และมันถูกใช้ร่วมกันระหว่างตัวควบคุมทั้งหมดภายในแอปปัจจุบัน เมื่อ Angularjs สร้างอินสแตนซ์ของออบเจ็กต์บริการมันลงทะเบียนออบเจ็กต์บริการนี้ด้วยชื่อบริการที่ไม่ซ้ำกัน ดังนั้นทุกครั้งที่เราต้องการอินสแตนซ์ของบริการ Angular ค้นหารีจิสทรีสำหรับชื่อบริการนี้และส่งกลับการอ้างอิงไปยังวัตถุบริการ เช่นที่เราสามารถเรียกใช้วิธีการเข้าถึงคุณสมบัติอื่น ๆ บนวัตถุบริการ คุณอาจมีคำถามว่าคุณสามารถใส่คุณสมบัติวิธีการในขอบเขตวัตถุของตัวควบคุม! ดังนั้นทำไมคุณต้องการบริการวัตถุ รู้รอบคือ: บริการต่าง ๆ ถูกใช้ร่วมกันในขอบเขตของคอนโทรลเลอร์ หากคุณวางคุณสมบัติ / วิธีการบางอย่างไว้ในวัตถุขอบเขตของคอนโทรลเลอร์จะสามารถใช้ได้กับขอบเขตปัจจุบันเท่านั้น
ดังนั้นหากมีสามขอบเขตคอนโทรลเลอร์ให้เป็นคอนโทรลเลอร์ A, คอนโทรลเลอร์ B และคอนโทรลเลอร์ C ทั้งหมดจะใช้อินสแตนซ์บริการเดียวกัน
<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 จะถูกผูกไว้กับ serviceInstance แทนที่จะส่งคืนวัตถุเรายังสามารถส่งคืนฟังก์ชั่นค่าอื่น ๆ สิ่งที่เราจะส่งคืนจะสามารถใช้ได้กับอินสแตนซ์บริการ
ตัวอย่าง:
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 พยายามสร้างอินสแตนซ์ของวัตถุบริการ เวลานี้ใช้คำสำคัญ 'ใหม่' และเรียกใช้ฟังก์ชันตัวสร้าง
var serviceInstance = new fnServiceConstructor();
ในฟังก์ชั่นคอนสตรัคเตอร์เราสามารถใช้คีย์เวิร์ด 'this' เพื่อเพิ่มคุณสมบัติ / เมธอดให้กับออบเจ็กต์บริการ ตัวอย่าง:
//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 ();
บริการใช้ฟังก์ชันตัวสร้างและ Angular เรียกใช้ฟังก์ชันตัวสร้างนี้โดยใช้คำหลัก 'ใหม่' สำหรับการสร้างอินสแตนซ์ของบริการ serviceInstance = ใหม่ fnServiceConstructor ();
ผู้ให้บริการกำหนดฟังก์ชั่น providerConstructor ฟังก์ชัน providerConstructor นี้กำหนดฟังก์ชั่นโรงงาน$ ได้รับ Angular call $ get () เพื่อสร้างออบเจ็กต์บริการ ไวยากรณ์ของผู้ให้บริการมีข้อได้เปรียบเพิ่มเติมของการกำหนดค่าบริการวัตถุก่อนที่จะได้รับอินสแตนซ์ serviceInstance = $ รับ ();
หลายคนที่นี่ชี้ให้เห็นอย่างถูกต้องโรงงานผู้ให้บริการและแม้กระทั่งค่าและค่าคงที่เป็นรุ่นของสิ่งเดียวกัน คุณสามารถแยกความหมายทั่วไป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');
});
ฉันสังเกตเห็นสิ่งที่น่าสนใจเมื่อเล่นกับผู้ให้บริการ
การมองเห็นของ injectables จะแตกต่างกันสำหรับผู้ให้บริการกว่าสำหรับบริการและโรงงาน ถ้าคุณประกาศ AngularJS "คงที่" (ตัวอย่างเช่นmyApp.constant('a', 'Robert');
) คุณสามารถฉีดเข้าไปในบริการโรงงานและผู้ให้บริการ
แต่ถ้าคุณประกาศ "ค่า" AngularJS (ตัวอย่างเช่น. myApp.value('b', {name: 'Jones'});
) คุณสามารถฉีดเข้าไปในบริการและโรงงาน แต่ไม่เข้าไปในฟังก์ชันการสร้างผู้ให้บริการ อย่างไรก็ตามคุณสามารถฉีดเข้าไปใน$get
ฟังก์ชันที่คุณกำหนดไว้สำหรับผู้ให้บริการของคุณ สิ่งนี้ถูกกล่าวถึงในเอกสารของ AngularJS แต่พลาดง่าย คุณสามารถค้นหาได้ในหน้า% ให้ในส่วนที่เกี่ยวกับค่าและวิธีการคงที่
<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:วัตถุประสงค์ของโรงงานก็เหมือนกันกับบริการอย่างไรก็ตามในกรณีนี้เราสร้างวัตถุใหม่และเพิ่มฟังก์ชั่นเป็นคุณสมบัติของวัตถุนี้และในตอนท้ายเราจะส่งคืนวัตถุนี้
AngularJS Provider:จุดประสงค์นี้เหมือนเดิมอีกครั้ง แต่ Provider ให้ผลลัพธ์เป็นฟังก์ชัน $ get
การกำหนดและการใช้บริการโรงงานและผู้ให้บริการมีการอธิบายที่http://www.dotnetfunda.com/articles/show/3156/difference-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
คำตอบที่ดีทั้งหมดอยู่แล้ว ผมอยากจะเพิ่มจุดอีกไม่กี่บนบริการและโรงงาน พร้อมกับความแตกต่างระหว่างบริการ / โรงงาน และสามารถมีคำถามเช่น:
เริ่มต้นด้วยความแตกต่างระหว่างการบริการและโรงงาน:
ทั้งสองเป็น Singletons : เมื่อใดก็ตามที่ Angular พบว่าเป็นการพึ่งพาครั้งแรกมันจะสร้างอินสแตนซ์ของการบริการ / โรงงานเพียงครั้งเดียว เมื่อสร้างอินสแตนซ์แล้วอินสแตนซ์เดียวกันจะถูกใช้ตลอดไป
สามารถใช้ในการจำลองวัตถุที่มีพฤติกรรม : พวกเขาทั้งสองสามารถมีวิธีการตัวแปรสถานะภายในและอื่น ๆ แม้ว่าวิธีที่คุณเขียนรหัสนั้นจะแตกต่างกัน
บริการ:
yourServiceName()
บริการเป็นฟังก์ชั่นคอนสตรัคและเชิงมุมจะยกตัวอย่างโดยเรียกใหม่ นี่หมายถึงสองสิ่ง
this
ฟังก์ชั่นและตัวแปรเช่นจะมีคุณสมบัติของnew yourServiceName(
) มันจะรับthis
วัตถุที่มีคุณสมบัติทั้งหมดที่คุณใส่ไว้ตัวอย่างตัวอย่าง:
angular.service('MyService', function() {
this.aServiceVariable = "Ved Prakash"
this.aServiceMethod = function() {
return //code
};
});
เมื่อ Angular ฉีด
MyService
บริการนี้เป็นตัวควบคุมที่ขึ้นอยู่กับมันตัวควบคุมนั้นจะได้รับสิ่งMyService
ที่สามารถเรียกใช้งานฟังก์ชั่นเช่น 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
ฟังก์ชันผู้เรียกจะได้รับ Object นั้นแทนที่จะเป็นอินสแตนซ์นี้
ซึ่งหมายความว่าคุณสามารถคัดลอกตัวอย่างจากโรงงานโดยทั่วไปจากด้านล่างแทนที่factory
ด้วยservice
และมันจะทำงาน:
angular.service('MyService', function($http) {
var api = {};
api.aServiceMethod= function() {
return $http.get('/users');
};
return api;
});
ดังนั้นเมื่อ Angular สร้างบริการของคุณด้วย MyService ใหม่ () มันจะได้รับออบเจ็กต์ api นั้นแทน MyService instance
นี่คือพฤติกรรมสำหรับค่าที่ซับซ้อนใด ๆ (วัตถุฟังก์ชั่น) แต่ไม่ได้สำหรับประเภทดั้งเดิม
โรงงาน:
โรงงานคือฟังก์ชั่นเก่าแบบธรรมดาที่คืนค่า ค่าส่งคืนคือสิ่งที่ได้รับการฉีดเข้าไปในสิ่งที่ขึ้นอยู่กับโรงงาน รูปแบบโรงงานทั่วไปใน Angular คือการส่งคืนวัตถุที่มีฟังก์ชั่นเป็นคุณสมบัติเช่นนี้
angular.factory('MyFactory', function($http) {
var api = {};
api.aFactoryMethod= function() {
return $http.get('/users');
};
return api;
});
ค่าที่ฉีดสำหรับการพึ่งพาจากโรงงานคือค่าส่งคืนของโรงงานและไม่จำเป็นต้องเป็นวัตถุ มันอาจเป็นฟังก์ชั่น
คำตอบสำหรับคำถาม 1 และ 2 ข้างต้น:
ส่วนใหญ่เพียงใช้การใช้โรงงานเพื่อทุกสิ่ง พฤติกรรมของพวกเขานั้นง่ายต่อการเข้าใจ ไม่มีทางเลือกที่จะทำเกี่ยวกับว่าจะคืนค่าหรือไม่และยิ่งกว่านั้นไม่มีข้อบกพร่องที่จะแนะนำถ้าคุณทำสิ่งผิด
ฉันยังคงอ้างถึงพวกเขาว่า "บริการ" เมื่อฉันพูดถึงการฉีดพวกเขาเป็นการอ้างอิงแม้ว่า
พฤติกรรมบริการ / โรงงานคล้ายกันมากและบางคนจะบอกว่าอย่างใดอย่างหนึ่งก็ดี ค่อนข้างจะเป็นเรื่องจริง แต่ฉันคิดว่ามันง่ายกว่าที่จะทำตามคำแนะนำของไกด์นำเที่ยวของ John Papa และติดกับโรงงาน **
ชี้แจงเพิ่มเติมคือโรงงานสามารถสร้างฟังก์ชั่น / ดั้งเดิมในขณะที่บริการไม่สามารถ ตรวจสอบjsFiddleนี้ตาม Epokk's: http://jsfiddle.net/skeller88/PxdSP/1351/ 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 วิธี) - น้ำตาล syntactic มากกว่าทางผู้ให้บริการ / ผู้รับ
มีService vs Factory
บางส่วนได้รับการคุ้มครอง:
https://www.youtube.com/watch?v=BLzNCkPn3ao
บริการเป็นเรื่องเกี่ยวกับnew
คำสำคัญจริง ๆ ซึ่งเรารู้ว่าทำสิ่งที่ 4:
prototype
วัตถุcontext
กับthis
this
และFactoryเป็นข้อมูลเกี่ยวกับ Factory Pattern - ประกอบด้วยฟังก์ชั่นที่คืนค่าออบเจกต์เช่น Service
และวิดีโอแบบสั้น / สั้นนี้: ครอบคลุมผู้ให้บริการด้วย : https://www.youtube.com/watch?v=HvTZbQ_hUZY (ที่นั่นคุณจะเห็นว่าพวกเขาไปจากโรงงานสู่ผู้ให้บริการได้อย่างไร)
สูตรผู้ให้บริการส่วนใหญ่จะใช้ในการกำหนดค่าแอปก่อนที่แอปจะเริ่มต้น / เริ่มต้นอย่างสมบูรณ์
หลังจากอ่านโพสต์ทั้งหมดมันสร้างความสับสนให้ฉันมากขึ้น .. แต่ก็ยังเป็นข้อมูลที่มีค่าทั้งหมด .. ในที่สุดฉันก็พบตารางต่อไปนี้ซึ่งจะให้ข้อมูลกับการเปรียบเทียบแบบง่าย ๆ
และสำหรับผู้เริ่มต้นเข้าใจ: -นี่อาจไม่ถูกต้องกรณีใช้ แต่ในระดับสูงนี่คือสิ่งที่เราใช้สำหรับทั้งสาม
angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})
สำหรับสถานการณ์พื้นฐานโรงงานและการบริการมีพฤติกรรมเหมือนกัน
นี่คือบางส่วนของรหัสไก่เนื้อฉันได้มาเป็นแม่แบบของรหัสสำหรับวัตถุใน AngularjS ฉันใช้ Car / 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
;
ใช้เป็นข้อมูลอ้างอิงในหน้านี้และเอกสารประกอบ (ซึ่งดูเหมือนว่าจะมีการปรับปรุงอย่างมากตั้งแต่ครั้งสุดท้ายที่ฉันดู) ฉันได้รวบรวมการสาธิตโลกจริง (-ish) ดังต่อไปนี้ซึ่งใช้ผู้ให้บริการ 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);
}]);
};
ดังนั้นโดยพื้นฐานแล้วในทั้งสองกรณีคุณได้รับผู้ให้บริการ $ ได้รับการตั้งค่าให้กับฟังก์ชั่นที่คุณให้ไว้ แต่คุณสามารถให้อะไรมากกว่า $ ได้ตามที่คุณสามารถให้ในผู้ให้บริการ () สำหรับ config block
ฉันรู้คำตอบที่ดีมาก แต่ฉันต้องแบ่งปันประสบการณ์การใช้
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 Custom Services โดยใช้วิธีการจากโรงงานบริการและผู้ให้บริการ
ฉันพบวิดีโอนี้ซึ่งอธิบายเกี่ยวกับวิธีการบริการและผู้ให้บริการอย่างชัดเจนสำหรับการพัฒนา AngularJS Custom Services:
https://www.youtube.com/watch?v=oUXku28ex-M
รหัสที่มา: http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service
รหัสที่โพสต์ที่นี่จะถูกคัดลอกมาจากแหล่งข้อมูลข้างต้นโดยตรงเพื่อประโยชน์ของผู้อ่าน
รหัสสำหรับบริการที่กำหนดเองที่ใช้ "โรงงาน" มีดังต่อไปนี้ (ซึ่งไปพร้อมกับเวอร์ชันการซิงค์และ async พร้อมกับการเรียกใช้บริการ 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;
}
]);
รหัสสำหรับวิธีการ "บริการ" สำหรับ Custom Services (ค่อนข้างคล้ายกับ 'โรงงาน' แต่แตกต่างจากมุมมองของไวยากรณ์):
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");
});
};
}]);
รหัสสำหรับวิธีการ "ผู้ให้บริการ" สำหรับ Custom Services (จำเป็นถ้าคุณต้องการพัฒนาบริการที่สามารถกำหนดค่าได้):
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");
}]);
ในที่สุด UI ที่ทำงานกับบริการใด ๆ ข้างต้น:
<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 ของ Yaakov )
บริการ :
ไวยากรณ์:
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
วัตถุบางอย่างภายในผู้ให้บริการและโดยปกติจะมาพร้อมกับค่าเริ่มต้นที่เราสามารถเขียนทับในขั้นตอนต่อมาซึ่งเราสามารถกำหนดค่าแอปพลิเคชันทั้งหมดโรงงาน:โรงงานที่คุณสร้างวัตถุภายในโรงงานจริง ๆ แล้วส่งคืน
บริการ:บริการที่คุณเพิ่งมีฟังก์ชั่นมาตรฐานที่ใช้คำหลักนี้เพื่อกำหนดฟังก์ชั่น
ผู้ให้บริการ:ผู้ให้บริการที่มี $ ให้คุณกำหนดและมันสามารถใช้ในการรับวัตถุที่ส่งกลับข้อมูล
โดยพื้นฐานแล้วผู้ให้บริการโรงงานและบริการคือบริการทั้งหมด Factory เป็นกรณีพิเศษของบริการเมื่อทุกสิ่งที่คุณต้องการคือฟังก์ชั่น $ get () ช่วยให้คุณเขียนด้วยรหัสน้อยลง
ความแตกต่างที่สำคัญระหว่างบริการโรงงานและผู้ให้บริการคือความซับซ้อน บริการเป็นรูปแบบที่ง่ายที่สุดโรงงานมีความแข็งแกร่งขึ้นเล็กน้อยและผู้ให้บริการสามารถกำหนดค่าได้ในขณะทำงาน
นี่เป็นบทสรุปของการใช้เมื่อใด:
Factory : ค่าที่คุณให้ต้องถูกคำนวณตามข้อมูลอื่น
บริการ : คุณกำลังส่งคืนวัตถุด้วยวิธีการ
ผู้ให้บริการ : คุณต้องการที่จะสามารถกำหนดค่าในระหว่างขั้นตอนการกำหนดค่าวัตถุที่จะถูกสร้างขึ้นก่อนที่จะสร้างขึ้น ใช้ผู้ให้บริการส่วนใหญ่ในการกำหนดค่าแอปก่อนที่แอปจะเริ่มต้นได้อย่างสมบูรณ์
1. บริการเป็นวัตถุเดี่ยวที่สร้างขึ้นเมื่อจำเป็นและไม่เคยทำความสะอาดจนกว่าจะสิ้นสุดวงจรชีวิตของแอปพลิเคชัน (เมื่อปิดเบราว์เซอร์) ตัวควบคุมจะถูกทำลายและทำความสะอาดเมื่อไม่ต้องการอีกต่อไป
2. วิธีที่ง่ายที่สุดในการสร้างบริการคือใช้วิธีการจากโรงงาน () วิธีการจากโรงงาน () ช่วยให้เราสามารถกำหนดบริการโดยส่งคืนวัตถุที่มีฟังก์ชั่นบริการและข้อมูลการบริการ ฟังก์ชั่นการให้คำจำกัดความบริการเป็นที่ที่เราให้บริการแบบฉีดเช่น $ http และ $ q Ex:
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 ใช้เพื่อดึงข้อมูลอินสแตนซ์ของวัตถุตามที่กำหนดโดย ผู้ให้บริการ " ไม่ใช่บริการไม่ใช่จากโรงงาน แต่เป็นผู้ให้บริการ
และคำตอบที่ดีกว่านี้ก็คือ: "บริการ Angular ถูกสร้างขึ้นโดยโรงงานบริการโรงงานบริการเหล่านี้เป็นฟังก์ชั่นซึ่งในทางกลับกันถูกสร้างขึ้นโดยผู้ให้บริการผู้ให้บริการเป็นฟังก์ชั่นคอนสตรัคเตอร์ เรียกว่า $ get ซึ่งเก็บฟังก์ชั่นบริการโรงงาน "
ดังนั้นผู้ให้บริการหลักและหัวฉีดและทั้งหมดจะอยู่ในสถานที่ :) และมันน่าสนใจใน typescript เมื่อ $ get สามารถนำไปใช้ในผู้ให้บริการโดยรับมรดกจาก IServiceProvider