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. -
Take a look at
services.js
which uses$resource
(ngResource) to create a Book service:
services.js
angular.module('bookApp').service('Book', function($resource) {
return $resource('https://super-crud.herokuapp.com/books/:id');
});
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()
, and delete()
methods in our BooksController
controller!
controllers.js
angular
.module('bookApp')
.controller('BooksController', BooksController);
function BooksController (Book) {
this.newBook = {}; // will hold user input for new book
this.books = Book.query(); // returns all the books
this.createBook = createBook;
this.updateBook = updateBook;
this.deleteBook = deleteBook;
function updateBook(book) {
Book.update({id: book._id}, book);
book.displayEditForm = false;
};
function createBook(){
Book.save(this.newBook);
// TODO: clear the form!
// TODO: display the new book in the list of books!
};
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.
services.js
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
},
query: {
isArray: true,
transformResponse: function(data) {
return angular.fromJson(data).books; // this grabs the books from the response data: `{books: [...]}`
}
}
});
});
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!
- Can you modify (aka "transformResponse" ) the incoming list of books and change
_id
toid
before it gets to the controller? - Can you create a seperate view for each book? I.E. Each title should link to a view that shows only the details for that book (
localhost:8000/#/books/10
). 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.
- Use
###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!