Lecture11 Handout
Lecture11 Handout
Now, we are ready to start working with our application. I will assume that you
created a new directory, called rottenpotatoes , to hold the application code. Let us
create the skeleton of application using the yeoman angular generator. The latter
can be done with the following command:
yo angular --coffee
Please note that we are using the option --coffee because we want to use
coffeescript. Sure enough, if we omit this option, yeomans plugin will generate
javascript code. Additionally, yo uses the name of the current directory as the
name for the application. Thats why you will see some references to
rottenpotatoesApp .
In my case, I was required to clean up npm cache before lauching code
generation with yeoman. The command to do this is the following:
npm cache clean
Yeomans code generator will ask you to customize your project. Lets keep the
default configuration. However, since the code generator install the support to
SASS (i.e., a -simplified- language for specifying CSS stylesheets) you will be
required to install Rubys compass gem. Please be patient because the setup will
take a little while!
You can run the seed application, by means of the following command:
grunt serve
to the controller:
'use strict'
app = angular.module('rottenpotatoesApp')
app.controller 'MoviesIndexController', ($scope) ->
$scope.movies = [
{ id: 0, title: 'Aladdin', rating: 'G', release_date: new Date() }
{ id: 1, title: 'Amelie', rating: 'PG', release_date: new Date() }
]
Finally, we have to change the file app/index.html so as to load all the above files
whenever we lauch the application. To this end, you have to add the following lines
One important thing to note is the fact that both the Controller and the view share
a reference to the list of movies. In the Controller side, the list of movies is refered
by $scope.movies . In the View side, the list of movies is rendered via the statement
{{movies}} .
2. CONTROLLER: You can add another file for the new controller. However, it is
possible to add the code for the controller in the existing file (i.e.,
movies_controllers.js ). If you opt for adding a new file, then do not forget to
modify index.html to include the new file. The code for the controller will be
introduced a bit later.
3. ROUTE: Add the information about the route to the file scripts/app.coffee , as
follows:
.when '/movies/new',
templateUrl: 'views/movies/new.html'
controller: 'MoviesNewController'
In this case, the view pushes information back to the controller. To this end, the
input elements are annotated with the directive ng-model . For instance, the first
text field captures the information of the movie title via the annotation
ng-model="title" . In the controller side, we will access to that information via
$scope.title .
The directive ng-options="r for r in ['G', 'PG', 'PG-13', 'R'] allows us to specify
a set of options on the drop-down menu that serves to specify the rating of a
movie.
Finally, the directive ng-click="addMovie()" serves a specifying that the method
$scope.addMovie() on the controller will be executed when the button is clicked.
Movies Service
The information held by controllers is transient and is lost whenever we change
from one web page to another. If we use an analogy with Rails, at the beginning of
every controller action, we have to query the Model with the information provided
via the hash params, and only afterwards we would be able to process a request.
The persistence of information is therefore delegated to the model. In Angular, we
will delegate a sort of persistence to services. Note that there a several classes of
services and I will introduce first a very simple one, which will allow us to hold all
the information in main memory. Now, lets take a look at the code (please copy
the snippet into the file scripts/services/movies_services.coffee ).
'use strict'
app = angular.module('rottenpotatoesApp')
app.service 'MoviesService', ->
movies = []
all: ->
movies
add: (movie) ->
movies.push(movie)
As you can see, the service uses an array (i.e., movies ) on which will store all the
movies. The service also provides two methods: all() that returns all the movies,
and add() that adds a new movie at the end of the array.
Now we have to wire up the service with the controllers that we have defined.
First, lets change the implementation of MoviesIndexController (in the file
scripts/controller/movies_controllers.coffee ).
'use strict'
app = angular.module('rottenpotatoesApp')
app.controller 'MoviesIndexController', ['$scope', 'MoviesService', ($scope, M
oviesService) ->
$scope.movies = MoviesService.all()
]
Note the changes in the syntax. First, all the declaration of the controller is now
Note the changes in the syntax. First, all the declaration of the controller is now
packaged as an array. Within this array, we can find a list of strings corresponding
with the components we expect that the angularjs dependency injector will provide
(namely, $scope and MoviesService ). Note that we are repeating the same list now
as the list of parameters of the anonymous function that defines the behavior of
the controller. Finally, you can see that now we replaced the literal array that we
were using for initializing $scope.movies . The same variable is now set to the value
returned by MoviesService.all() .
Let us now introduce the implementation of MoviesNewController . Note that I
decided to put both of the controllers in the same file (but you can certainly
separate them). Copy the following code at the end of the file
scripts/controllers/movies_controllers.coffee .
app.controller 'MoviesNewController', ['$scope', '$location', 'MoviesService',
($scope, $location, MoviesService) ->
$scope.addMovie = ->
MoviesService.add {title: $scope.title, rating: $scope.rating, release_da
te: $scope.release_date}
$location.path '/movies'
]
As you can see, this controller also relies on MoviesService . This service as well as
the references to $scope and $location are by dependency injection. This
controller provides only the implementation to the method addMovie() which is
launched by clicking the Save button in the new.html view. Please note that all the
information captured by the form is available via $scope related variables (e.g.,
$scope.title , etc.).
The last addition is the call $location.path '/movies' that redirects the control to
the path /movies .