Angularjs 将$scope注入到角度服务函数()中
我有一项服务:Angularjs 将$scope注入到角度服务函数()中,angularjs,angular-ui,angular-ui-router,Angularjs,Angular Ui,Angular Ui Router,我有一项服务: angular.module('cfd') .service('StudentService', [ '$http', function ($http) { // get some data via the $http var path = 'data/people/students.json'; var students = $http.get(path).then(function (resp) { return resp.da
angular.module('cfd')
.service('StudentService', [ '$http',
function ($http) {
// get some data via the $http
var path = 'data/people/students.json';
var students = $http.get(path).then(function (resp) {
return resp.data;
});
//save method create a new student if not already exists
//else update the existing object
this.save = function (student) {
if (student.id == null) {
//if this is new student, add it in students array
$scope.students.push(student);
} else {
//for existing student, find this student using id
//and update it.
for (i in students) {
if (students[i].id == student.id) {
students[i] = student;
}
}
}
};
但是,当我调用save()
时,我无法访问$scope
,并获取ReferenceError:$scope未定义。因此,(对我来说)合乎逻辑的步骤是为save()提供$scope
,因此我还必须向服务提供/注入它。如果我这样做:
.service('StudentService', [ '$http', '$scope',
function ($http, $scope) {
我得到以下错误:
错误:[$injector:unpr]未知提供程序:$scopeProvider服务是单例的,在服务中注入作用域是不符合逻辑的(事实上,您不能在服务中注入作用域)。您可以将范围作为参数传递,但这也是一个糟糕的设计选择,因为您将在多个位置编辑范围,从而使调试变得困难。处理作用域变量的代码应该进入控制器,服务调用进入服务。您可以在控制器中实现$watch
,以观察服务上的属性变化,然后更新$scope
上的属性,而不是试图修改服务中的$scope
。以下是您可以在控制器中尝试的示例:
angular.module('cfd')
.controller('MyController', ['$scope', 'StudentService', function ($scope, StudentService) {
$scope.students = null;
(function () {
$scope.$watch(function () {
return StudentService.students;
}, function (newVal, oldVal) {
if ( newValue !== oldValue ) {
$scope.students = newVal;
}
});
}());
}]);
需要注意的一点是,在您的服务中,为了使students
属性可见,它需要位于服务对象或此
上,如下所示:
this.students = $http.get(path).then(function (resp) {
return resp.data;
});
您看到被注入控制器的$scope
不是某种服务(像其他可注入的东西一样),而是一个scope对象。可以创建许多范围对象(通常是从父范围继承的)。所有作用域的根是$rootScope
,您可以使用任何作用域(包括$rootScope
)的$new()
方法创建新的子作用域
范围的目的是“粘合”应用程序的表示和业务逻辑。将$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.
});
};
}
]);
另请参见此
小更新:
在谈论使用服务,但不使用service()
函数创建服务时,请用几句话避免可能出现的混淆
.service('StudentService', [ '$http',
function ($http) {
// get some data via the $http
var path = '/students';
//save method create a new student if not already exists
//else update the existing object
this.save = function (student, doneCallback) {
$http.post(
path,
{
params: {
student: student
}
}
)
.then(function (resp) {
doneCallback(resp.data); // when the async http call is done, execute the callback
});
}
.controller('StudentSaveController', ['$scope', 'StudentService', function ($scope, StudentService) {
$scope.saveUser = function (user) {
StudentService.save(user, function (data) {
$scope.message = data; // I'm assuming data is a string error returned from your REST API
})
}
}]);
引用:
角度服务是由服务工厂创建的单例对象。这些服务工厂是由服务提供商创建的功能。服务提供者是构造函数。实例化时,它们必须包含名为$get
的属性,该属性包含服务工厂功能。
[…]
“$provide
服务具有其他帮助器方法来注册服务,而无需指定提供程序:
- 提供者(提供者)-向$injector注册服务提供者
- 常量(obj)-注册提供者和服务可以访问的值/对象李>
- 值(obj)-注册只能由服务而不是提供者访问的值/对象李>
- 工厂(fn)-注册服务工厂函数fn,该函数将包装在服务提供者对象中,其$get属性将包含给定的工厂函数李>
- 服务(类)-注册一个构造函数,该类将封装在服务提供者对象中,其$get属性将使用给定的构造函数实例化一个新对象
基本上,它说的是每个角度服务都是使用$provide.provider()
注册的,但是对于更简单的服务有“快捷”方法(其中两种是service()
和factory()
)。
这一切都“归结”为一项服务,因此使用哪种方法没有多大区别(只要该方法能够满足您的服务需求)
顺便说一句,provider
vsservice
vsfactory
是新来者最容易混淆的概念之一,但幸运的是,有大量的资源(这里就这样)让事情变得更简单。(随便看看。)
(我希望这会清除它-如果没有,请告诉我。)您可以让您的服务完全不知道作用域,但在控制器中允许异步更新作用域
您遇到的问题是,您不知道http调用是异步进行的,这意味着您无法立即获得可能的值。比如说,
var students = $http.get(path).then(function (resp) {
return resp.data;
}); // then() returns a promise object, not resp.data
有一个简单的方法来解决这个问题,就是提供一个回调函数
.service('StudentService', [ '$http',
function ($http) {
// get some data via the $http
var path = '/students';
//save method create a new student if not already exists
//else update the existing object
this.save = function (student, doneCallback) {
$http.post(
path,
{
params: {
student: student
}
}
)
.then(function (resp) {
doneCallback(resp.data); // when the async http call is done, execute the callback
});
}
.controller('StudentSaveController', ['$scope', 'StudentService', function ($scope, StudentService) {
$scope.saveUser = function (user) {
StudentService.save(user, function (data) {
$scope.message = data; // I'm assuming data is a string error returned from your REST API
})
}
}]);
表格:
<div class="form-message">{{message}}</div>
<div ng-controller="StudentSaveController">
<form novalidate class="simple-form">
Name: <input type="text" ng-model="user.name" /><br />
E-mail: <input type="email" ng-model="user.email" /><br />
Gender: <input type="radio" ng-model="user.gender" value="male" />male
<input type="radio" ng-model="user.gender" value="female" />female<br />
<input type="button" ng-click="reset()" value="Reset" />
<input type="submit" ng-click="saveUser(user)" value="Save" />
</form>
</div>
{{message}
名称:
电子邮件:
性别:男
女性
(function () {
getDataFactory = function ($http)
{
return {
callWebApi: function (reqData)
{
var dataTemp = {
Page: 1, Take: 10,
PropName: 'Id', SortOrder: 'Asc'
};
return $http({
method: 'GET',
url: '/api/PatientCategoryApi/PatCat',
params: dataTemp, // Parameters to pass to external service
headers: { 'Content-Type': 'application/Json' }
})
}
}
}
patientCategoryController = function ($scope, getDataFactory) {
alert('Hare');
var promise = getDataFactory.callWebApi('someDataToPass');
promise.then(
function successCallback(response) {
alert(JSON.stringify(response.data));
// Set this response data to scope to use it in UI
$scope.gridOptions.data = response.data.Collection;
}, function errorCallback(response) {
alert('Some problem while fetching data!!');
});
}
patientCategoryController.$inject = ['$scope', 'getDataFactory'];
getDataFactory.$inject = ['$http'];
angular.module('demoApp', []);
angular.module('demoApp').controller('patientCategoryController', patientCategoryController);
angular.module('demoApp').factory('getDataFactory', getDataFactory);
}());
ngapp.factory('Scopes', function (){
var mem = {};
return {
store: function (key, value) { mem[key] = value; },
get: function (key) { return mem[key]; }
};
});
ngapp.controller('myCtrl', ['$scope', 'Scopes', function($scope, Scopes) {
Scopes.store('myCtrl', $scope);
}]);
ngapp.factory('getRoute', ['Scopes', '$http', function(Scopes, $http){
// there you are
var $scope = Scopes.get('myCtrl');
}]);