在$scope
你看到被注入控制器是不是有些服务(如的注射材料的其余部分),而是一个范围对象。可以创建许多作用域对象(通常是从父作用域继承的原型)。所有作用域的根都是$rootScope
,您可以使用$new()
任何作用域(包括$rootScope
)的方法来创建新的子作用域。
范围的目的是将应用程序的表示和业务逻辑“粘合在一起”。将a传递$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
:
Angular 服务是由服务工厂创建的单例对象。这些服务工厂是由服务提供商创建的功能。该服务提供商是构造函数。实例化后,它们必须包含一个名为的属性$get
,该属性包含服务工厂功能。
[...]
...的$provide
服务有额外的辅助方法,而不指定提供商注册服务:
- provider(provider) -向$ injector注册服务提供商
- constant(obj) -注册可以由提供者和服务访问的值/对象。
- value(obj) -注册一个只能由服务而非提供者访问的值/对象。
- factory(fn) -注册服务工厂函数fn,该函数将包装在服务提供程序对象中,该对象的$ get属性将包含给定的工厂函数。
- service(class) -注册一个构造函数,该类将包装在服务提供者对象中,该类的$ get属性将使用给定的构造函数实例化一个新对象。
基本上,它说的是每个Angular服务都是使用来注册的$provide.provider()
,但是对于更简单的服务,有“捷径”方法(其中两个是service()
和factory()
)。
所有这些都“归结为”服务,因此使用哪种方法并没有多大区别(只要该方法可以满足服务要求)。
顺便说一句,provider
vs vs service
vs factory
是Angular新手最容易混淆的概念之一,但幸运的是,有很多资源(在SO上)使事情变得更容易。(只需四处搜索。)
(我希望这可以解决-如果不能,请告诉我。)