То, $scope
что вы видите, внедряемое в контроллеры, не является какой-то службой (как и остальная часть вводимого материала), а является объектом Scope. Могут быть созданы многие объекты области видимости (обычно прототипически наследуемые от родительской области). Корнем всех областей видимости является область, $rootScope
и вы можете создать новую дочернюю область, используя $new()
метод любой области (включая $rootScope
).
Цель Scope - «склеить» презентацию и бизнес-логику вашего приложения. Нет смысла передавать 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 (поставщик) - регистрирует поставщика услуг с помощью инжектора $
- константа (obj) - регистрирует значение / объект, к которому могут получить доступ провайдеры и службы.
- value (obj) - регистрирует значение / объект, к которому могут получить доступ только службы, а не поставщики.
- factory (fn) - регистрирует функцию фабрики служб, fn, которая будет заключена в объект поставщика службы, чье свойство $ get будет содержать данную фабричную функцию.
- service (class) - регистрирует функцию-конструктор, класс, который будет заключен в объект поставщика услуг, чье свойство $ get будет создавать экземпляр нового объекта с использованием данной функции-конструктора.
По сути, это говорит о том, что каждая служба Angular регистрируется с использованием $provide.provider()
, но есть "ярлыки" для более простых служб (два из которых - service()
и factory()
).
Все «сводится» к сервису, поэтому не имеет большого значения, какой метод вы используете (если требования к вашему сервису могут быть удовлетворены этим методом).
Кстати, provider
vs service
vs factory
- одна из самых запутанных концепций для новичков в Angular, но, к счастью, есть много ресурсов (здесь, на SO), чтобы упростить задачу. (Просто поищите вокруг.)
(Надеюсь, это проясняет ситуацию - дайте мне знать, если это не так.)
service
илиfactory
- вы закончите u службой и Angular . Просто убедитесь, что вы понимаете, как каждый из них работает и соответствует ли он вашим потребностям.$scope.students
пустым, если вызов ajax не завершен? Или$scope.students
будет частично заполнен, если этот блок кода работает?students.push(student);
Вместо того, чтобы пытаться изменить
$scope
внутри службы, вы можете реализовать$watch
в своем контроллере, чтобы отслеживать изменения свойства в вашей службе, а затем обновить свойство в$scope
. Вот пример, который вы можете попробовать в контроллере:Следует отметить, что в вашей службе, чтобы
students
свойство было видимым, оно должно находиться в объекте Service илиthis
примерно так:источник
Что ж (длинный) ... если вы настаиваете на
$scope
доступе внутри службы, вы можете:Создать службу получения / установки
Введите его и сохраните в нем область контроллера
Теперь поместите область действия в другую службу
источник
Сервисы являются одиночными, и нелогично внедрять область видимости в службу (а это действительно так, вы не можете внедрить область в службу). Вы можете передать область видимости в качестве параметра, но это также плохой выбор дизайна, потому что область видимости будет редактироваться в нескольких местах, что затруднит отладку. Код для работы с переменными области действия должен находиться в контроллере, а вызовы службы - в службу.
источник
Вы можете сделать так, чтобы ваша служба полностью не знала об области, но в вашем контроллере разрешите асинхронное обновление области.
Проблема, с которой вы столкнулись, заключается в том, что вы не знаете, что HTTP-вызовы выполняются асинхронно, что означает, что вы не получаете значение сразу, как могли бы. Например,
Есть простой способ обойти это - предоставить функцию обратного вызова.
Форма:
Это удалило часть вашей бизнес-логики для краткости, и я на самом деле не тестировал код, но что-то вроде этого будет работать. Основная концепция заключается в передаче обратного вызова от контроллера службе, которая будет вызвана позже в будущем. Если вы знакомы с NodeJS, это та же концепция.
источник
.then
методов обещания являются анти-шаблоном .Попал в такое же затруднительное положение. В итоге я получил следующее. Итак, здесь я не внедряю объект области видимости в фабрику, а устанавливаю область $ в самом контроллере, используя концепцию обещания, возвращаемого службой $ http .
источник
Код для работы с переменными области действия должен находиться в контроллере, а вызовы службы - в службу.
Вы можете вводить
$rootScope
с целью использования$rootScope.$broadcast
и$rootScope.$on
.В противном случае избегайте инъекций
$rootScope
. Видеть$rootScope
есть, но можно использовать во зло .источник