Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

AngularJS routing with multiple views


May 08, 2021 AngularJS


Table of contents


Routes with multiple views

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.

  • When you navigate app/index.html you'll jump to app/index.html/#/phones list of phones appears in your browser.
  • When you click on the phone link, url becomes a specific phone and a phone details page appears.

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.

Dependence

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

Multiple views, routes, and layout templates

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.

A reminder of DI, injectors, and providers

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:

  • Load the module definitions that you specify in your app.
  • Register all providers defined in the module definition.
  • When asked to do this, inject a specified function and some necessary dependencies (services) that are inertly instantiated through their providers.

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.

Note: Only the provider can be injected into the 'config' function. So you can't $routeProvider 'phonelistctrl' into 'PhoneListCtrl'.

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.

Template

$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.

Note: Starting with AngelJS v1.2, 'ngRoute' in its own module must be loaded by loading an additional 'angular-route.js' file, and we download the 'angular-route.js' file via Bower above.

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>
Todo! AngularJS routing with multiple views

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.

The application module

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.

Controller

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.

Test

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.

Experiment

  • Try adding a 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.
:: In 'PhoneCatCtrl', create a new module with 'this.hero' and 'Zoro', called 'hero'. I n 'PhoneListCtrl', let's mask it with 'this.hero' and 'Batman'. I n 'PhoneDetailCtrl', we'll use 'this.hero' and 'Captain Proton'. And then put '

hero = {{hero}}

'Add to all three templates .html'index', 'phone-list.html and 'phone-.html'. When you open the app, you'll see that scope inheritance and template property masking do some wonders.

Summarize

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.