Quello $scope
che vedi essere iniettato nei controller non è un servizio (come il resto delle cose iniettabili), ma è un oggetto Scope. È possibile creare molti oggetti ambito (di solito ereditando in modo prototipico da uno scope padre). La radice di tutti gli ambiti è $rootScope
ed è possibile creare un nuovo ambito figlio utilizzando il $new()
metodo di qualsiasi ambito (incluso il $rootScope
).
Lo scopo di uno Scope è "incollare" la presentazione e la logica di business della tua app. Non ha molto senso passare a $scope
in un servizio.
I servizi sono oggetti singoli utilizzati (tra le altre cose) per condividere dati (ad esempio tra diversi controller) e generalmente incapsulano pezzi di codice riutilizzabili (poiché possono essere iniettati e offrono i loro "servizi" in qualsiasi parte della tua app che ne ha bisogno: controller, direttive, filtri, altri servizi ecc.).
Sono sicuro che vari approcci funzionerebbero per te. Uno è questo:
dal momento che StudentService
è responsabile della gestione dei dati degli studenti, puoi avere la possibilità di StudentService
tenere un array di studenti e lasciarlo "condividere" con chiunque possa essere interessato (ad esempio il tuo $scope
). Questo ha ancora più senso, se ci sono altre visualizzazioni / controller / filtri / servizi che devono avere accesso a quelle informazioni (se non ce ne sono in questo momento, non sorprenderti se iniziano a comparire presto).
Ogni volta che viene aggiunto un nuovo studente (utilizzando il save()
metodo del servizio ), l'array di studenti del servizio verrà aggiornato e anche ogni altro oggetto che condivide quell'array verrà aggiornato automaticamente.
In base all'approccio descritto sopra, il tuo codice potrebbe essere simile a questo:
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.
});
};
}
]);
Una cosa a cui dovresti prestare attenzione quando utilizzi questo approccio è di non riassegnare mai l'array del servizio, perché in tal caso qualsiasi altro componente (ad esempio gli ambiti) farà ancora riferimento all'array originale e l'app si interromperà.
Ad esempio, per cancellare l'array in StudentService
:
/* DON'T DO THAT */
var clear = function () { students = []; }
/* DO THIS INSTEAD */
var clear = function () { students.splice(0, students.length); }
Vedi anche questa breve demo .
PICCOLO AGGIORNAMENTO:
Poche parole per evitare la confusione che può sorgere parlando di utilizzare un servizio, ma non crearlo con la service()
funzione.
Citando i documenti su$provide
:
Un servizio angolare è un oggetto singleton creato da una fabbrica di servizi . Queste fabbriche di servizi sono funzioni che, a loro volta, vengono create da un fornitore di servizi . I fornitori di servizi sono funzioni di costruzione. Quando vengono istanziati, devono contenere una proprietà chiamata $get
, che contiene la funzione di fabbrica di servizi .
[...]
... il $provide
servizio ha metodi di supporto aggiuntivi per registrare i servizi senza specificare un provider:
- provider (provider) - registra un provider di servizi con $ injector
- costante (obj) - registra un valore / oggetto a cui possono accedere fornitori e servizi.
- value (obj) - registra un valore / oggetto a cui possono accedere solo i servizi, non i provider.
- factory (fn) - registra una funzione factory di servizi, fn, che verrà racchiusa in un oggetto provider di servizi, la cui proprietà $ get conterrà la funzione factory data.
- service (class) - registra una funzione di costruzione, classe che sarà racchiusa in un oggetto del fornitore di servizi, la cui proprietà $ get istanzerà un nuovo oggetto utilizzando la funzione di costruzione data.
Fondamentalmente, quello che dice è che ogni servizio Angular è registrato usando $provide.provider()
, ma ci sono metodi "scorciatoia" per servizi più semplici (due dei quali sono service()
e factory()
).
Tutto "si riduce" a un servizio, quindi non fa molta differenza quale metodo usi (a patto che i requisiti per il tuo servizio possano essere coperti da quel metodo).
A proposito, provider
vs service
vs factory
è uno dei concetti più confusi per i nuovi arrivati di Angular, ma fortunatamente ci sono molte risorse (qui su SO) per rendere le cose più facili. (Basta cercare in giro.)
(Spero che questo chiarisca tutto, fammi sapere se non lo fa.)