Введение $scope в угловую сервисную функцию()
у меня есть:
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 is not defined. Поэтому логическим шагом (для меня) является предоставление save () с помощью $scope, и поэтому я также должен предоставить / ввести его в service. Так что если я делаю это так:
.service('StudentService', [ '$http', '$scope',
function ($http, $scope) {
Я получаю следующую ошибку:
ошибка: [$injector:unpr] неизвестный поставщик: $scopeProvider
ссылка в ошибке (Вау, это аккуратно!) дайте мне знать, что это связано с инжектором и может иметь отношение к порядку объявления файлов js. Я попытался переупорядочить их в index.html, но я думаю, что это что-то более простое, например, я вводил их.
использование Angular-UI и Angular-UI-Router
6 ответов:
The
$scopeто, что вы видите, вводится в контроллеры, не является какой-то Службой (как и остальная часть вводимого материала), но является объектом Scope. Многие объекты области могут быть созданы (обычно прототипически наследуя от родительской области). Корень всех областей является$rootScopeи вы можете создать новую дочернюю область с помощью$new()метод любой области (включая$rootScope).цель области состоит в том, чтобы "склеить" презентацию и бизнес-логику вашего приложение. Это не имеет большого смысла, чтобы пройти
$scopeв сервис.службы-это одноэлементные объекты, используемые (среди прочего) для обмена данными (например, между несколькими контроллерами) и обычно инкапсулируют многоразовые фрагменты кода (поскольку они могут быть введены и предлагать свои "услуги" в любой части вашего приложения, которое нуждается в них: контроллеры, директивы, фильтры, другие службы и т. д.).
я уверен, что разные подходы будут работать для вас. Один из них таков:
ПосколькуStudentServiceотвечает за работу с данными студентов, вы можете иметьStudentServiceдержите массив студентов и пусть он "поделиться" его с тем, кто может быть заинтересован (например, ваш$scope). Это имеет еще больший смысл, если есть другие представления / контроллеры / фильтры / службы, которые должны иметь доступ к этой информации (если их нет прямо сейчас, не удивляйтесь, если они скоро начнут появляться).
Каждый раз, когда новый студент добавляется (с помощью сервисаsave()метод), собственный массив сервиса учащиеся будут обновлены, и каждый другой объект, совместно использующий этот массив, также будет автоматически обновляться.исходя из описанного выше подхода, ваш код может выглядеть так:
angular.module('cfd', []) .factory('StudentService', ['$http', function ($http) { 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 */ 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; } } } }; /* Populate the students array with students from the server */ $http.get(path).success(function (data) { 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 StudentService.save(student); // The $scope's `students` array will be automatically updated // since it references the StudentService's `students` array // Do some more $scope-specific stuff, // e.g. show a notification }; } ]);
Одна вещь, которую вы должны быть осторожны при использовании этого подхода,-это никогда не назначать массив службы, потому что тогда любые другие компоненты (например, области) будут по-прежнему ссылаться на исходный массив, и ваше приложение сломается.
Например, чтобы очистить массив вStudentService:/* DON'T DO THAT */ var clear = function () { students = []; } /* DO THIS INSTEAD */ var clear = function () { students.splice(0, students.length); }Смотрите также, это короткое демо.
НЕБОЛЬШОЕ ОБНОВЛЕНИЕ:
несколько слов, чтобы избежать путаницы, которая может возникнуть при разговоре об использовании сервиса, но не создавая его с помощью
вместо того, чтобы пытаться изменить
$scopeв рамках сервиса, вы можете реализовать$watchв вашем контроллере, чтобы посмотреть свойство на вашем сервисе для изменений, а затем обновить свойство на$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вот так:this.students = $http.get(path).then(function (resp) { return resp.data; });
хорошо (долго) ... если вы настаиваю иметь
$scopeдоступ внутри службы, вы можете:создать службу getter / setter
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'); }]);
службы являются синглетами, и не логично вводить область в Службу (что действительно так, вы не можете вводить область в службу). Вы можете передать область в качестве параметра, но это также плохой выбор дизайна, потому что у вас будет область, редактируемая в нескольких местах, что затрудняет отладку. Код для работы с переменными области должен входить в контроллер, а вызовы службы - в службу.
вы можете сделать свою службу полностью неосведомленной о области, но в вашем контроллере разрешить асинхронное обновление области.
проблема, с которой вы столкнулись, заключается в том, что вы не знаете, что 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>этого удалены некоторые бизнес-логики для краткости и я на самом деле не проверял код, но что-то вроде этого будет работать. Основная концепция заключается в передаче обратного вызова от контроллера к службе, которая вызывается позже в будущем. Если вы знакомы с NodeJS, это та же концепция.
попал в такое же положение. В итоге я получил следующее. Так что здесь я не впрыскиваю объект scope в завод, а устанавливаю $ scope в самом контроллере используется понятие обещание возвращено $http сервис.
(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); }());
Comments