This sprint we will:
- Reorganize our code with client-side routing and template files, using
ngRoute
. - Add a client-side route and a template file for viewing details of an album.
Before this sprint, you should:
- Be able to describe templates and layouts.
- Be ready to look up documentation for
ngRoute
Module and these features:
ngRoute
is a separate Angular module. We've had its code included sneakily in the<head>
ofindex.html
since sprint 1 (muhahaha):
<script src="/vendor/angular-route/angular-route.min.js"></script>
Now we just need to tell Angular that we'd like to use it in this app. In app.js
, add the ngRoute
module as a dependency available everywhere in our tunely app -- here's the syntax:
angular
.module('tunely', ['ngRoute'])
.controller('AlbumsIndexController', AlbumsIndexController);
ngRoute
allows us to configure client-side routes in our app. We can define what we want to happen at every different (front-end) URL within our application. We'll configure these routes using Angular's.config
, and we usually pass it in a function that's also just calledconfig
. Add in a.config
line right after you set up the tunely app:
angular
.module('tunely', ['ngRoute'])
.config(config)
.controller('AlbumsIndexController', AlbumsIndexController);
- Let's define that
config
function. WithngRoute
, we'll use$routeProvider
to set up routes. We'll also use$locationProvider
to help make cleaner URLs (by default,ngRoute
d URLs have a/#/
in them). Both$routeProvider
and$locationProvider
are part of thengRoute
module. Copy the followingconfig
function into yourapp.js
:
config.$inject = ['$routeProvider', '$locationProvider'];
function config( $routeProvider, $locationProvider ) {
$routeProvider
.when('/', {
templateUrl: 'This template will show the homepage, with all ablums!',
controllerAs: 'albumsIndexCtrl',
controller: 'AlbumsIndexController'
})
.when('/albums/:id', {
templateUrl: 'This template will show an album!',
controllerAs: 'albumsShowCtrl',
controller: 'AlbumsShowController'
});
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
}
Check what happens when you visit the /
URL and a /albums/:id
URL for some album in your browser now.
- So far, we've been putting all of our view code in
index.html
, but we'd like a bit more modularity. Theindex.html
file will still have the<head>
and any<body>
content that doesn't change for different pages.
Most of our page content will move to HTML into files inside a templates
folder. Create a templates
folder inside of the project's views
folder.
-
Inside of the
templates
folder, create an HTML file calledalbums.html
. Move most of the HTML fromindex.html
to this new file -- the entire div that starts<div class="container" ng-controller="AlbumsIndexController as albumsIndexCtrl">
. -
Update the
config
to use this template new file by giving itstemplateUrl
on the/
path:.when('/', { templateUrl: '/templates/albums.html', controllerAs: 'albumsIndexCtrl', controller: 'AlbumsIndexController' })
-
Now that we have a template file, our
config
function will take care of setting which controller should be used on that page. Theng-controller
statement inalbums.html
has been made redundant; remove it. -
Back in
index.html
, we've removed all our content! We need to add adiv
that tells Angular where the partial template file for this URL should get loaded. In the same place where you removed the priordiv
, add this line:
<div ng-view></div>
- Now if you reload your page, everything will look exactly the same!!!
That's not very exciting... Actually it kind of is! Now have a more modular app with the ability to expand into many different files.
-
Along these same lines, we can move the controller code out into its own file. To get started, create a
controllers
folder inside of/public/scripts
. -
Inside of the
controllers
folder, create aAlbumsIndexController.js
file. Just like any other JavaScript file, we need to include this file in ourindex.html
. Add it below where we loadapp.js
so that the tunely app is created before we try to give it controllers.
<script src="scripts/app.js"></script>
<script src="scripts/controllers/AlbumsIndexController.js"></script>
- Move the contents of
AlbumsIndexController
into the new file. When all is said and done, our newAlbumsIndexController.js
should look like this:
angular
.module('tunely')
.controller('AlbumsIndexController', AlbumsIndexController);
AlbumsIndexController.$inject = ['$http'];
function AlbumsIndexController ( $http ) {
...
}
Notice in the first line that we need to explicitly state what module
this controller is a part of. We don't restate tunely's dependencies. We're referencing our app's module, not creating a new one.
- Without
AlbumsIndexController
,app.js
looks like this:
angular
.module('tunely', ['ngRoute'])
.config(config);
function config ($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: '/templates/albums.html',
controllerAs: 'albumsIndexCtrl',
controller: 'AlbumsIndexController'
})
.when('/albums/:id', {
templateUrl: '/templates/albums-show.html',
controllerAs: 'albumsShowCtrl',
controller: 'AlbumsShowController'
})
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
}
- Now make sure everything loads properly in your browser. Debug any issues.
-
Creating a new route: You may have noticed the
config
function refers to an/albums/:id
route. This route is going to show us the details of individual albums. -
This route will be accessible when the user clicks on an album name. To create this link, surround where you display the
albumName
with an<a>
tag that links to/albums/:id
. Use theng-href
directive for the url portion, like so
<a ng-href="albums/{{album._id}}">{{album.name}}</a>
-
Try clicking on this link in your browser, and notice the error messages.
-
Create two new files:
/views/templates/albums-show.html
and/public/scripts/controllers/AlbumsShowController.js
. Don't forget to includeAlbumsShowController.js
inindex.html
. -
These files will be similar to
albums.html
andAlbumsIndexController.js
. Reference those two files to create a basic structure for your new files and to check the connections between them. -
In
AlbumsShowController.js
, we need toGET
the data for one album. To do that, we need to grab the_id
of that data object that we're interested in from the URL.
Angular provides us with a component called $routeParams
that allows us access the URL path's parameters. To use $routeParams
, we $inject
it in the controller. After it's injected, the parameters from the URL are available inside the $routeParams
object.
AlbumsShowController.$inject = ['$http', '$routeParams'];
function AlbumsShowController ( $http, $routeParams ) {
var vm = this;
console.log($routeParams);
$http({
method: 'GET',
url: '/api/albums/'+ // how can we get the id? (hint: check console log from above)
}).then(function successCallback(json) {
vm.album = json.data;
});
}
- Add HTML to the view in
albums-show.html
to display all this data. You should show each of the songs on the album's show page.