สิ่ง$scope
ที่คุณเห็นว่าถูกฉีดเข้าไปในคอนโทรลเลอร์ไม่ใช่บริการบางอย่าง (เช่นส่วนที่เหลือของสิ่งที่ฉีดได้) แต่เป็นวัตถุขอบเขต สามารถสร้างวัตถุขอบเขตจำนวนมากได้ (โดยปกติจะสืบทอดจากขอบเขตหลัก) รากของขอบเขตทั้งหมดคือ$rootScope
และคุณสามารถสร้างขอบเขตย่อยใหม่โดยใช้$new()
วิธีการของขอบเขตใดก็ได้ (รวมถึง$rootScope
)
จุดประสงค์ของขอบเขตคือ "รวม" งานนำเสนอและตรรกะทางธุรกิจของแอปของคุณ มันไม่สมเหตุสมผลมากที่จะผ่าน$scope
เข้าสู่บริการ
บริการเป็นอ็อบเจ็กต์เดี่ยวที่ใช้ (นอกเหนือจากสิ่งอื่น ๆ ) เพื่อแบ่งปันข้อมูล (เช่นระหว่างตัวควบคุมหลายตัว) และโดยทั่วไปจะห่อหุ้มโค้ดที่ใช้ซ้ำได้ (เนื่องจากสามารถแทรกและเสนอ "บริการ" ของพวกเขาในส่วนใดก็ได้ของแอปของคุณที่ต้องการ: คอนโทรลเลอร์, คำสั่งตัวกรองบริการอื่น ๆ ฯลฯ )
ฉันแน่ใจว่าแนวทางต่างๆจะได้ผลสำหรับคุณ หนึ่งคือ:
เนื่องจากStudentService
เป็นผู้รับผิดชอบในการจัดการกับข้อมูลของนักเรียนคุณสามารถจัดStudentService
เก็บข้อมูลของนักเรียนไว้หลายกลุ่มและปล่อยให้ "แบ่งปัน" กับใครก็ตามที่อาจสนใจ (เช่นของคุณ$scope
) สิ่งนี้สมเหตุสมผลยิ่งขึ้นหากมีมุมมอง / ตัวควบคุม / ตัวกรอง / บริการอื่น ๆ ที่จำเป็นต้องเข้าถึงข้อมูลนั้น (หากยังไม่มีในตอนนี้อย่าแปลกใจถ้าพวกเขาเริ่มปรากฏขึ้นในไม่ช้า)
ทุกครั้งที่มีการเพิ่มนักเรียนใหม่ (โดยใช้save()
วิธีการของบริการ) อาร์เรย์ของนักเรียนของบริการเองจะได้รับการอัปเดตและออบเจ็กต์อื่น ๆ ที่แชร์อาร์เรย์นั้นจะได้รับการอัปเดตโดยอัตโนมัติเช่นกัน
ตามแนวทางที่อธิบายไว้ข้างต้นโค้ดของคุณอาจมีลักษณะดังนี้:
angular.
module('cfd', []).
factory('StudentService', ['$http', '$q', function ($http, $q) {
var path = 'data/people/students.json';
var students = [];
// In the real app, instead of just updating the students array
// (which will be probably already done from the controller)
// this method should send the student data to the server and
// wait for a response.
// This method returns a promise to emulate what would happen
// when actually communicating with the server.
var save = function (student) {
if (student.id === null) {
students.push(student);
} else {
for (var i = 0; i < students.length; i++) {
if (students[i].id === student.id) {
students[i] = student;
break;
}
}
}
return $q.resolve(student);
};
// Populate the students array with students from the server.
$http.get(path).then(function (response) {
response.data.forEach(function (student) {
students.push(student);
});
});
return {
students: students,
save: save
};
}]).
controller('someCtrl', ['$scope', 'StudentService',
function ($scope, StudentService) {
$scope.students = StudentService.students;
$scope.saveStudent = function (student) {
// Do some $scope-specific stuff...
// Do the actual saving using the StudentService.
// Once the operation is completed, the $scope's `students`
// array will be automatically updated, since it references
// the StudentService's `students` array.
StudentService.save(student).then(function () {
// Do some more $scope-specific stuff,
// e.g. show a notification.
}, function (err) {
// Handle the error.
});
};
}
]);
สิ่งหนึ่งที่คุณควรระวังเมื่อใช้แนวทางนี้คืออย่ากำหนดอาร์เรย์ของบริการซ้ำเพราะส่วนประกอบอื่น ๆ (เช่นขอบเขต) จะยังคงอ้างอิงอาร์เรย์เดิมและแอปของคุณจะพัง
เช่นการล้างอาร์เรย์ในStudentService
:
/* DON'T DO THAT */
var clear = function () { students = []; }
/* DO THIS INSTEAD */
var clear = function () { students.splice(0, students.length); }
ดูการสาธิตสั้น ๆนี้ด้วย
อัปเดตเล็กน้อย:
คำสองสามคำเพื่อหลีกเลี่ยงความสับสนที่อาจเกิดขึ้นขณะพูดคุยเกี่ยวกับการใช้บริการ แต่ไม่ได้สร้างขึ้นด้วยservice()
ฟังก์ชัน
อ้างถึงเอกสารเมื่อ$provide
:
เชิงมุมบริการเป็นวัตถุเดี่ยวที่สร้างขึ้นโดยโรงงานบริการ เหล่านี้โรงงานบริการฟังก์ชั่นซึ่งในที่สุดก็จะถูกสร้างขึ้นโดยผู้ให้บริการ ผู้ให้บริการที่มีฟังก์ชั่นคอนสตรัค เมื่อสร้างอินสแตนซ์พวกเขาจะต้องมีคุณสมบัติที่เรียกว่า$get
ซึ่งมีฟังก์ชันโรงงานบริการ
[... ]
... $provide
บริการมีวิธีการช่วยเหลือเพิ่มเติมในการลงทะเบียนบริการโดยไม่ต้องระบุผู้ให้บริการ:
- ผู้ให้บริการ (Provider) - ลงทะเบียนผู้ให้บริการกับ $ injector
- ค่าคงที่ (obj) - ลงทะเบียนค่า / วัตถุที่ผู้ให้บริการและบริการสามารถเข้าถึงได้
- ค่า (obj) - ลงทะเบียนค่า / วัตถุที่สามารถเข้าถึงได้โดยบริการเท่านั้นไม่ใช่ผู้ให้บริการ
- factory (fn) - ลงทะเบียนฟังก์ชันโรงงานบริการ fn ซึ่งจะรวมอยู่ในอ็อบเจ็กต์ผู้ให้บริการซึ่งคุณสมบัติ $ get จะมีฟังก์ชันโรงงานที่กำหนด
- บริการ (คลาส) - ลงทะเบียนฟังก์ชันตัวสร้างคลาสที่จะถูกรวมไว้ในอ็อบเจ็กต์ของผู้ให้บริการซึ่งคุณสมบัติ $ get จะสร้างอินสแตนซ์อ็อบเจ็กต์ใหม่โดยใช้ฟังก์ชันตัวสร้างที่กำหนด
โดยทั่วไปสิ่งที่กล่าวคือทุกบริการ Angular ได้รับการลงทะเบียนโดยใช้$provide.provider()
แต่มีวิธี "ทางลัด" สำหรับบริการที่ง่ายกว่า (สองวิธีคือservice()
และfactory()
)
ทุกอย่าง "เดือด" สำหรับบริการดังนั้นจึงไม่ได้สร้างความแตกต่างมากนักว่าคุณใช้วิธีใด (ตราบเท่าที่วิธีการนั้นครอบคลุมข้อกำหนดสำหรับบริการของคุณ)
BTW, provider
vs service
vs factory
เป็นหนึ่งในแนวคิดที่สับสนที่สุดสำหรับผู้มาใหม่ Angular แต่โชคดีที่มีทรัพยากรมากมาย (ที่นี่ใน SO) เพื่อให้ง่ายขึ้น (เพียงแค่ค้นหารอบ ๆ )
(ฉันหวังว่าจะกระจ่างขึ้น - แจ้งให้เราทราบหากไม่เป็นเช่นนั้น)