I am trying to make sure that I am using all the parts of my angular application correctly / all the right code is in the right place.
I came across this article http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/ which has an example application with data stored in an array inside a service. I feel like the way the app is structured makes sense (but could be completely wrong).
Can I trigger a $broadcast to happen when a $resource action fires in the same way that I trigger a $broadcast when the array is updated in this code.
myApp.service( 'Book', function( $rootScope ) {
var service = {
books: [
{ title: "Magician", author: "Raymond E. Feist" },
{ title: "The Hobbit", author: "J.R.R Tolkien" }
],
addBook: function ( book ) {
service.books.push( book );
//console.log(service.books);
$rootScope.$broadcast( 'books.update' );
}
}
return service;
});
Here is a plunker of a working example http://plnkr.co/edit/y56oQvrvK6OgXJEPJSv7?p=previewin
If I can do what I'm asking then the other question is should I? I see the alternative as having all the interactions with service (and the $resource in it) take place in the controller (which is what I have done until now)
Any thoughts or suggestions would be greatly appreciated.
Yes, you can do what you're asking. A $resource
will return an object/array that has a $promise
property. You can use this promise to know when the server request succeeds/fails.
In the success/fail handler, you do $rootScope.$broadcast()
as needed. Here's a service that uses the query()
method of a $resource
to do this:
EDIT
Here is the full service implementation. Note you can skin this cat many ways, so these are just some example ideas.
myApp.service( 'Book', function($rootScope, $resource ) {
var myResource = $resource('/books/:id', { id: '@id' } );
var books;
var service = {
// this function broadcasts the result
getBooks: function() {
myResource.query(
function(response) {
$rootScope.$broadcast('it.worked', response);
},
function(error) {
$rootScope.$broadcast('it.failed', error);
}
);
},
// this function returns the $resource and also keeps a copy
// so someone else may get the data with getBooksResult()
getBooks2: function() {
books = myResource.query();
books.$promise(
function(response) {
// if you still need to broadcast...
$rootScope.$broadcast('it.worked');
},
function(error) {
$rootScope.$broadcast('it.failed');
}
);
return books;
},
getBookResult: function() {
return books;
}
}
return service;
});
Should you do this?
I don't see a lot of harm in doing this, but you should at least give it some thought. You are going to $broadcast()
an event from the top of your application's scope hierarchy down to every other scope in your app.
This will likely send the event to scopes that don't care at all about the event. Keep in mind that there are could be many scopes in your app (created by controllers/directives). Probably not a big deal in most cases.
The nice thing about $resource
is that it returns you an empty object, that is later filled in with the server response. So often times you don't need resort to broadcasting the result :) Views that use the resource's return value will update automagically. And controller's that need the value (or error) can use the $promise
from the $resource
as I've shown above.