May 08, 2021 AngularJS
In this step, you'll learn how to add routes by using an Angel module called 'ngRoute', create a layout template, and bind an app with multiple views.
app/index.html
you'll jump to
app/index.html/#/phones
list of phones appears in your browser.
Reset the workspace to step 7
git checkout -f step-7
Refresh your browser or check this step online: Step 7 Live Demo
The differences between steps 6 and 7 are listed below. You can see the full difference in GitHub.
The routing feature added in this step is provided by the angular in the
ngRoute
module, which is distributed separately from the core Angular framework.
We use
Bower
to install client dependencies.
This step updates the
bower.json
profile to include new dependencies:
{
"name": "angular-phonecat",
"description": "A starter project for AngularJS",
"version": "0.0.0",
"homepage": "https://github.com/angular/angular-phonecat",
"license": "MIT",
"private": true,
"dependencies": {
"angular": "1.4.x",
"angular-mocks": "1.4.x",
"jquery": "~2.1.1",
"bootstrap": "~3.1.1",
"angular-route": "1.4.x"
}
}
New
"angular-route": "1.4.x"
tells bower to install the v1.4x compatible version of the angular-router component.
We'll tell bower to download and install the dependency.
If you have a bower installed globally, you can run bower install only
bower install
and we have pre-configured npm to run the bower installation for us:
npm install
Our applications are becoming more and more complex. B
efore the seventh step, the app gives our users a single view (a list of phones) and all the template codes are
index.html
file.
The next step in building your app is to add a view that shows the details of each device in our list.
To add a detail view, we can extend
index.html
to include two sets of views, but that will soon become confusing. S
o instead of this approach, we
index.html
into a "layout template." T
his is a template that is often used for all views in our app.
The other Local Layout Templates are then included in the layout template based on the current Route, resulting in a complete view that is presented to the user.
Declare$ $routeProvider routes in Angular through the application $route provider of the service. T his service makes it easy to connect controllers, view templates, and the current location in the browser. With this feature, we can implement Deep Link, which allows us to use the browser's history (fallback and forward navigation) as well as bookmarks.
As you've noticed, dependency injection (DI) is at the heart of AngularJS, so it's important to know a little about how it works.
In application boot, Angular creates an injector that finds and injects all the services your app needs. T
he injector itself
$http
or
$route
the service is doing.
In fact, the injector doesn't even know if these services exist unless configured with the appropriate template definition.
The injector only appears in the following steps:
A provider is an object that provides (creates) a service instance and externally provides a configuration API that can be used to control the creation and runtime behavior of a service.
For
$route
$routeProvider
$routeProvider
an API that allows you to define routes for your application.
The Angular module addresses the issue of removing global state from the application and provides a way to configure the injector. C ompared to AMD .js or require modules, the Angular module does not attempt to solve script load order problems or lazy script access issues. These goals are completely independent, and the two module systems can exist in unsyn by example and achieve their goals.
To deepen your understanding of DI on Angular, see Understanding Dependency Injection.
$route
are often used
in conjunction with ngView
instructions.
ngView
directive is to include a view template for the current route in the layout template.
This makes it perfectly fit our
index.html
template.
app/index.html
:
<!doctype html>
<html lang="en" ng-app="phonecatApp">
<head>
...
<script src="/attachments/image/wk/angularjs/angular.js"></script>
<script src="/attachments/image/wk/angularjs/angular-route.js"></script>
<script src="/attachments/image/wk/angularjs/app.js"></script>
<script src="/attachments/image/wk/angularjs/controllers.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
We've added two
<script>
index file to load the external JavaScript file into our application:
angular-route.js
: Define the Angel
ngRoute
ngRoute
with routing.
app.js
: Now this file controls the root module of our application.
Note: We removed
index.html
template and replaced it with a line of code that contains a div with the element
ng-view
The code we've removed is put
phone-list.html
template:
app/partials/phone-list.html
:
<div class="container-fluid">
<div class="row">
<div class="col-md-2">
<!--Sidebar content-->
Search: <input ng-model="query">
Sort by:
<select ng-model="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
</div>
<div class="col-md-10">
<!--Body content-->
<ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail">
<a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}"></a>
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
<p>{{phone.snippet}}</p>
</li>
</ul>
</div>
</div>
</div>
We've also added a placeholder template for the phone details view:
app/partials/phone-detail.html
:
TBD: detail view for <span>{{phoneId}}</span>
Note that the
phoneId
are using
PhoneDetailCtrl
controller.
To enhance the organization of the application, we used
ngRoute
and we moved the
phonecatControllers
below).
We
index.html
angular-route.js
index and
controllers.js
phonecatControllers
H
owever, to use their code, we need to do more than that. W
e also need to add modules as a dependency on our applications.
By using the two apps as
phonecatApp
dependency list, we can use these instructions and the services they provide.
app/js/app.js
:
var phonecatApp = angular.module('phonecatApp', [
'ngRoute',
'phonecatControllers'
]);
...
Note that the second parameter is
angular.module
['ngRoute','phonecatControllers']
This array lists the
phonecatApp
depends.
...
phonecatApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
when('/phones/:phoneId', {
templateUrl: 'partials/phone-detail.html',
controller: 'PhoneDetailCtrl'
}).
otherwise({
redirectTo: '/phones'
});
}]);
Using
phonecatApp.config()
$routeProvider
which will be injected into our configuration function and used?
$routeProvider.when()
to define our routes.
Our application routing is defined as follows:
when('/phones')
When the URL mapping segment
/phones
T
his phone list view will be displayed.
To construct this view, Angular uses
phone-list.html
template, as well
PhoneListCtrl
controller.
when('/phones/:phoneId')
When the URL mapping segment
/phones/:phoneId
:phoneId
the variable part of the URL), the phone details view is displayed.
To construct a phone detail view, Angular uses
phone-detail.html
template
PhoneDetailCtrl
controller.
otherwise({redirectTo: '/phones'})
a redirect to /phones when the browser's address does
/phones
Once again, we used the
PhoneListCtrl
in the last step and added a new, empty
PhoneDetailCtrl
controller to the
app/js/controllers.js
file for the phone details view.
Note that in the second routing
:phoneId
parameter.
$route
uses the roote declaration
'/phones/:phoneId'
as a template to match the current URL. A
ll
:
by : notation are extracted and placed in ?
$routeParams
the object.
app/js/controllers.js
:
var phonecatControllers = angular.module('phonecatControllers', []);
phonecatControllers.controller('PhoneListCtrl', ['$scope', '$http',
function ($scope, $http) {
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
}]);
phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams',
function($scope, $routeParams) {
$scope.phoneId = $routeParams.phoneId;
}]);
Again, we've created a new module
phonecatControllers
F
or small AngularJS applications, only one template is typically created for all controllers, if only a few controllers are created. A
s your application expands, it's often important to refactor your code into additional modules.
For larger applications, you may want to create separate modules for all the main features of your app.
Because our application is small, we will add all our
phonecatControllers
module.
To automatically verify that everything is properly connected, we wrote an end-to-end test, navigated to different URLs, and checked that the correct view was rendered.
...
it('should redirect index.html to index.html#/phones', function() {
browser.get('app/index.html');
browser.getLocationAbsUrl().then(function(url) {
expect(url).toEqual('/phones');
});
});
describe('Phone list view', function() {
beforeEach(function() {
browser.get('app/index.html#/phones');
});
...
describe('Phone detail view', function() {
beforeEach(function() {
browser.get('app/index.html#/phones/nexus-s');
});
it('should display placeholder page with phoneId', function() {
expect(element(by.binding('phoneId')).getText()).toBe('nexus-s');
});
});
You can now run
npm run protractor
to see how the test runs.
index.html
{{orderProp}}
and you'll see that nothing happens, even if you're in the phone list view. T
his
orderProp
module is visible only within the scope of
PhoneListCtrl
management, which is associated with the element of
<div ng-view>
PhoneListCtrl
If you
phone-list.html
template, the binding will work as you expect.
With the success of routing settings and the realization of phone list vision, we are ready to go to Step 8 for more templates for mobile phone detail views.