Learning Objectives |
---|
Identify the benefits of using $resource over $http |
Establish a connection with an external RESTful API |
Experiment further with templating |
Explore the endless possibilities of UI-router |
Create your own 'ORM' between an external API and your app |
Built on the top of the $http
service, Angular’s $resource
is a service that lets you interact with RESTful backends easily. $resource
is very similar to models in Rails. In this tutorial, we're going to make use of a book API that can be found here: https://super-crud.herokuapp.com/books
. The request syntax of the books API follows the same pattern as the wine API that you used yesterday.
- Clone this repo and run
bower install
- The
$resource
service doesn’t come bundled with the main Angular script. Runbower install --save angular-resource
. - Add a link to the angular-resource module in your
index.html
(BELOW angular.js!):
<script src="bower_components/angular-resource/angular-resource.min.js"></script>
- Now you need to load the
$resource
module into your application.
angular.module('app', [..., 'ngResource']);
- In the application directory run a local server:
budo
#or
python -m SimpleHTTPServer 8000
# or
ruby -rwebrick -e 'WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot => Dir.pwd).start'
-
To use
$resource
inside your controller/service you need to declare a dependency on$resource
. The next step is calling the$resource()
function with your REST endpoint, as shown in the following example. This function call returns a$resource
class representation which can be used to interact with the REST backend. -
Create a
services.js
file and put your new$resource
service in it.
angular.module('bookApp').service('Book', function($resource) {
return $resource('https://super-crud.herokuapp.com/books/:id');
});
-
Add a script tag in your index.html linking to
services.js
after yourapp.js
script tag. -
The result of this function call is a resource class object which has the following five methods by default:
get()
,query()
,save()
,remove()
,delete()
(delete is an alias for remove) -
Now we can use the
get()
,query()
,save()
, anddelete()
methods in a controller:
angular
.module('bookApp')
.controller('BooksController', BooksController);
function BooksController (Book) {
this.book = Book.get({ id: 1 }, function(data) {
console.log(data);
}); // get() returns a single book
this.books = [];
this.newBook = {};
this.books = Book.query(); // returns all the books
this.createBook = createBook;
this.updateBook = updateBook;
this.deleteBook = deleteBook;
function updateBook(book) {
Book.get({ id: book.id }, function() {
Book.update({id: book.id}, book);
book.editForm = false;
});
};
function createBook(){
Book.save(this.newBook);
this.newBook = {}; // clear new book object
this.books = Book.query();
};
function deleteBook(book) {
Book.remove({id:book.id});
var bookIndex = this.books.indexOf(book);
this.books.splice(bookIndex, 1);
};
console.log("Controller loaded.");
};
The get()
function in the above snippet issues a GET request to /books/:id
.
The function query()
issues a GET request to /books
(notice there is no :id
).
The save()
function issues a POST request to /books
with the first argument as the book data. The second argument is a callback which is called when the data is saved.
- We are good to go for the create, read and delete parts of CRUD. However, since update can use either PUT or PATCH, we need to modify our custom factory
Book
as shown below.
angular.module('bookApp').factory('Book', BookFactory);
function BookFactory($resource) {
return $resource('https://super-crud.herokuapp.com/books/:id', { id: '@_id' }, {
update: {
method: 'PUT' // this method issues a PUT request
}
});
});
Note:
{ id: "@_id"}
is a mapping between the placeholder in our route (e.g./books/:id)
and the name of the key that holds the id in the book object. And since the database is mongoDB our id is_id
.
- Display all the books with all their attributes including the photo.
- Create a form to add a new book. Make it work!
- Add an edit button next to each book. Make it work!
- Add a delete button next to each book. Make it work!
Link the title
of each book to a view that shows only the details for that book. Hints:
- Use
ui-router
andng-view
to set up multiple views in your Angular app. - Use
$routeParams
to figure out which book to display. - Your view for a single book will have a different controller than your view that displays all books.
###Further Reading Angular $resource - Makes RESTful CRUD API soooooo sweet!
Angular UI-Router - Don't sweat this too much, we'll go over it tomorrow :)
Angular Factory vs Service vs Provider - Know the differences!