Click here to Skip to main content
13,147,183 members (27,945 online)
Click here to Skip to main content
Add your own
alternative version

Stats

3.4K views
53 downloads
4 bookmarked
Posted 13 Sep 2017
MIT

Angular 4 Navigation - A Simple Introduction

, 13 Sep 2017
Rate this:
Please Sign up or sign in to vote.
This is a very basic introduction to Angular 4 and the use of its navigation functionality.

Introduction

When I started learning Angular 4. I was surprised how different it was from the Angular 1.x. The most difficult aspect about Angular 4 is that the whole application architecture has changed. Even though I thought I was pretty good with Angular 1.x, It was still a little difficult for me to get started. The focus of this tutorial is about how to setup a basic Angular 4 application for page navigation. I would also like to discuss some of the gotchas I have noticed.

Running Hello World Sample Project

Here are the key steps I took to get this simple client side app to work. Here are the summary of steps:

  • Install the Latest Node JS.
  • Get the Hello World sample app.
  • Install All the Necessary NPM Packages.
  • Run the Sample App.
  • Change the Sample App with a new Design
  • Run the new App for Testing.

Install Node.JS

When I first started learning Angular 2/Angular 4 application development, I had a very old version of Node.JS installed. It was probably nine months old. When I used it on Angular 2 or Angular 4 application development, I was seeing weird errors which I can't find answers on search engines. After some struggle, I just gave up and installed newest version and everything just worked. So if you see weird errors and couldn't find out what went wrong, think about the version of Node.JS you are using. Upgrade if you must and see if it solves your problem.

The download page on nodejs.org is this: https://nodejs.org/en/download/

Getting the Hello World Sample App

The official Angular site has a basic walkthrough tutorial: The Hero Editor. I think it was a wonderful tutorial. The best basic tutorial on Angular 2/Angular 4 you can find on the web. Once you completed all the tutorial, you will no longer be a novice and can sufficiently work with Angular 4.

Anyways, I got sidetracked. For me, the easiest way to get started with Angular 4 is to get a working Hello World sample app. Do some customization of the application architecture, and I get an Angular application of my own.

Official Angular 4 tutorial provided a Hello World sample project, which is the one I used. The link to the sample app can be found: https://angular.io/guide/setup. At this page, on the top you can see the link called "download example", here is the link: https://angular.io/generated/zips/quickstart/quickstart.zip.

Once you download it, unzip it and put the unzipped source code in a meaningful folder, preferrably a folder with a short name like C:\sample\Hello. When you start running your code, the node_modules downloaded will have extremely long file names. Sometimes, this can be problematic if the base directory has a long file name.

Install Latest NPM Packages

Once you get the sample Hello World from angular.io, you can run npm command to install all the npm packages needed for the project. First you need to unzip the sample application. Go to the unzipped file directory, in there, should be a src directory. Go to this src directory, and run the following command:

npm install

This command will download and install all the necessary packages used by the sample project. It would take some time get all the packages. I would wait until all packages are downloaded and installed then go to the next step.

In case you are wondering where the packages are defined, go to the directory above src, and you will find a file called package.json. You can open this in a text editor, and in it, you will find two sections, 1) dependencies, and 2) devDependencies. These are the places where dependencies can be modified.

I used bootstrap for my sample application. So I added two new dependencies bootstrap (version 3.3.7 or above) and jquery (versiion 3.2.1 or above) to the end of the dependencies section:

"dependencies": {
   "@angular/animations": "~4.2.0",
   "@angular/common": "~4.2.0",
   "@angular/compiler": "~4.2.0",
   "@angular/compiler-cli": "~4.2.0",
   "@angular/core": "~4.2.0",
   "@angular/forms": "~4.2.0",
   "@angular/http": "~4.2.0",
   "@angular/platform-browser": "~4.2.0",
   "@angular/platform-browser-dynamic": "~4.2.0",
   "@angular/platform-server": "~4.2.0",
   "@angular/router": "~4.2.0",
   "@angular/tsc-wrapped": "~4.2.0",
   "@angular/upgrade": "~4.2.0",
   "angular-in-memory-web-api": "~0.3.2",
   "core-js": "^2.4.1",
   "rxjs": "5.0.1",
   "systemjs": "0.19.39",
   "zone.js": "^0.8.4",
   "jquery": "^3.2.1",
   "bootstrap": "^3.3.7"
}

After I modified the package.json file, I ran the same npm command again. And it will just add the newly specified packages.

Note that by default, the node packages (called mode_modules) are installed in the base directory (parent directory of src). I believe this has something to do with the relative path "../node_modules/@types/" in tsconfig.json. That is all you need to worry about relative paths, which will be described in the next section.

Running the Sample Project

To run the sample project, here is all you need to do:

npm start

after entering the command, the console will spit out a lot of output, and the default browser would load and display the sample output page of Hello World. Even though I made the change to the package.json file, it should not affect the original sample project.

If you can see Hello World on the browser, then you are ready for the second part of this tutorial, modified to have navigation, and some basic Angular 4 functionality for user interaction.

Angular 4 Navigation And Basic UI Interaction

In this section I am going to walk through the changes I have made to the Hello World project in order to get page navigation to work. To make this sample app a little bit more meaningful, I also included a little UI interaction on one of the pages. I will explain how that works as well.

Why Navigation?

When I looked into this, I found page navigation in Angular 4 as an interesting challenge. And it is very important to learn. So I decided to use this as an opportunity to learn the basic of it. Angular 4 is used to create single page application. But it does not mean the applicaion is composed with just one page. This would make the application very clogged. A better way is to split the functionality of an application into multiple functionality, and each functionality is served by its own pages. This feature is supported since Angular 1.x. I thought it would be simple to grasp. It turned out to be quite complicated.

I started out by reading the tutorial on angular.io. Then I read the source code of a project from angular.io. It turned out to be complicated. With that source code and some other resources I have forgotten where I found them (sorry), I was able to get it to work. In the next

The Core

The core of an Angular 2/Angular 4 applicaition is a file called main.ts. This file will be compiled into main.js and main.js will be included by the index.html file. The content of the main.ts looks like this:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

All this file does is bootstrap a class called AppModule, which is found in a file called app.module.ts. You can see the reference in above code snippet -- "./app/app.module". It tells where the file is, under the sub directory app, there is the file app.module.ts.

app.module.ts is the file that aggregates all the other necessary modules together. The content of this file is like this:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { AboutComponent } from './components/about.component';
import { HomeComponent } from './components/home.component';

@NgModule({
  imports:      [ BrowserModule, AppRoutingModule ],
  declarations: [ AppComponent, AboutComponent, HomeComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

I have to import AppRoutingModule, AppComponent, AboutComponent, and HomeComponent. These are all the modules and components I have made. There is just one class in this file, called "AppModule". The class has a decoration @NgModule, something similar to attribute in .NET framework and annotation in Java. The decoration does three different things:

  • It marks the class AppComponent as a bootstrapping class -- the start up class.
  • It marks three classes as controllers.
  • And it imports two modules. One of the module is the routing modulde.

The Start Up Class

The class AppComponent is marked as the star up class. It is defined in a file called app.component.ts. The content of this file looks like this:

import { Component } from "@angular/core";
import { Routes } from '@angular/router';
import { HomeComponent } from './components/home.component';
import { AboutComponent } from './components/about.component';

@Component({
  selector: 'my-app',
  templateUrl: './templates/app.tpl.html'
})
export class AppComponent { }

The top part of this file imports four different components. The first two are from the Angular library. They are needed because 1) the AppComponent class uses the @Component decorator; 2) the template which AppComponent is using, references the routerLink and router-outlet which is from the Routes class.

The second half of the file is the definition of the AppComponent. This class is like the two classes from previous sections, it has no properties or methods. And it has one decorator called @Component. For this class, the decorator @Component has two properties, one is called the selector. The other is called the templateUrl. The selector property defines on the index page what element will be replaced with a new UI template. The templateUrl defines what page template will be used. Essentially, AppComponent is the controller, and the templateUrl references the view which the controller can render.

The selector is assigned with value "my-app". So where is this my-app selector used? You can find it in the index.html. When index.html loads successfully, it will first start up main.js (which is transformed from main.ts), and it will load the app.module.js (which is transformed from app.module.ts). And if you remembered from previous sections, one of the modules loaded is the app.components.js (transformed from app.components.ts). That is how AppComponent is getting bootstrapped as a start up class.

Now, take a look at the template file for AppCompoment:

<div class="container">
<nav class="navbar navbar-default">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Brand</a>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav navbar-right">
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Navigation <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a [routerLink]="['/']">Home</a></li>
            <li><a [routerLink]="['/about']">About</a></li>
          </ul>
        </li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>
<router-outlet></router-outlet>
</div>

This page template can be viewed as two parts. The top part is a navigation menu. There is a lot of html code used to create this navigation menu. The real good part about it is the two anchors:

<li><a [routerLink]="['/']">Home</a></li>
<li><a [routerLink]="['/about']">About</a></li>

These two anchors defines different pages that can be navigated with in my sample project. One is the home page (navigation by "/"), and the other is the about page (navigation by "/about"). The mark up in the template html file does not make the navigation work. What makes it work is my AppRoutingModule. Which will be discussed next.

The Routing Module

The routing module is defined in the file app-routing.module.ts. The class is called AppRoutingModule. Here is something I learned when I finally got this class integrated with the rest of the project. The file name matters. I believe Angular 2/Angular 4 search the file system locally based on naming conventions. This is one thing I struggled with when I got to this point. I tried many different names for the routing module file, and included it in the app.module.ts. None worked, until I realized the file name should be app-routing.module.ts, which Angular probably interprets the class as AppRoutingModule in the file. Here is a hint, if you find your project broken and everything else seems to be correct, check your file name. The conversion rules are:

  • The file name should all be lower case.
  • The file name should be roughly the same as the class name. For example, when I export a class called AppRoutingModule, the file name would have "app" "routing" "module" in it.
  • Based on what the export file is, a module or a component. The file name will contain .module or .component, following by file extension .ts.
  • The class name contains multiple words, and these words will be lower case and separated by dash. For example AppRoutingModule, the word "AppRouting" would translate into file name as "app-routing".

There is also the problem of relative path. Some times, you can try finding the file from the current directory via relative path, and some time, you can just use absolute path. I will show examples for both.

The content of the app-routing.module.ts is as the following:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { AboutComponent } from './components/about.component';
import { HomeComponent } from './components/home.component';

export const appRoutes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent }
];
@NgModule({
  imports: [
    RouterModule.forRoot(
      appRoutes
    )
  ],
  exports: [
    RouterModule
  ]
})
export class AppRoutingModule {}

The file has three different parts:

  • The first part imports multiple modules or components into this file.
  • The second part will export an array called appRoutes. Inside this array, there two elements (objects) that define different routings.
  • The third part creates the AppRoutingModule module class. The class is decorated by @NgModule. Inside the decorator, the appRoutes is used to bind with the RouterModule, which is associated with the exported class AppRoutingModule.

This class shows a very basic routing module class. There are more complicated ways to define a routing module, you can see it in the sample project from angular.io. The most important part of the file is the declaration of the appRoutes array. In this declaration, each url path is associated with a component. A component, if you remember from before, is a controller that associated with a view. So in this case, the router module uses this appRoutes array to route the url path to a specific controller, which in term manage the associated view.

Next, we are going to see what these controllers look like.

The Controllers and The Views

I have created two pages for this navigation example. The controllers for these two pages are:

  • HomeComponent
  • AboutComponent

In Angular 4/Angular 2, there is no concept of congtroller anymore. Instead, a controller is more of a component. A view can be associated with a component through the @Component decorator, using the property of template or templateUrl of the @Component decorator. You can see this in previous section "The Start Up Class". In this section, I listed out the code of the index component. The two components for the pages of navigation look very similar. Here is hthe source code for the HomeComponent:

import { Component } from "@angular/core";

@Component({
  templateUrl: 'app/templates/home.tpl.html'
})
export class HomeComponent {
   public sunshine: string;
   
   constructor() {
      this.sunshine = "Cowboy Jackie";
   }
}

The way HomeComponent work is that the decorator @Component binds a view to this HomeComponent. The templateUrl defines where the view is. I personally prefer putting the view in a separated file, which makes the component class file a little cleaner. There are a lot of example out there that put the view file in the same compoent class file. This is not wrong, but I personally prefer separating the view into another file.

The class HomeComponent has a public property and a constructor. In this constructor, the public property is initialized to a string value "Cpwboy Jackie". The reason I did this is to test whether I can display the value of the property "sunshine" on the view. I want to point out that declaring the property as public is a bad practice. I should have used property accessors instead.

Here is the view for HomeComponent:

<div class="row">
   <div class="col-xs-12 col-sm-offset-1 col-sm-10">
      <div class="row">
         <div class="col-xs-12">
         <h3>Home</h3>
         <hr>
         <p>This is the home. Hello <span style="color: darkgreen">{{sunshine}}</span>!</p>
         </div>
      </div>
   </div>
</div>

In above html code, the way property "sunshine" was used as: {{sunshine}}. The double curly braces enclosure was angular's way of binding a model variable from the controller (a.k.a. component class) to the view. Note that such binding is two way. If the value on the view changed via user interaction, the value is also reflected in the controller (the component class) as well. To illustrate this and to show user interaction, I created the other controller called AboutComponent.

What I was trying to do with this about page is that on this page, there is a button. And there is a counter that was initialized to one. When user click on the button, the counter would increment by one. The change in value would shown on the page.

Here is the code for AboutComponent:

import { Component } from "@angular/core";

@Component({
  templateUrl: 'app/templates/about.tpl.html'
})
export class AboutComponent {
   public viewCount: number;
   
   constructor() {
      this.viewCount = 1;
   }
   
   public incrementViewCount() {
      this.viewCount = this.viewCount + 1;
   }
}

The source code for AboutComponent is very similar to the source code for HomeComponent, in terms of the class definition. This AboutComponent is just slightly more complex. First, I defined a public property called viewCount. Its type is number. Again, I must stress the fact that declaring this property as public is bad practice, one should use property accessor.

In the constructor, the property viewCount is set to one. There is also a public method called incrementViewCount. This method would increment the viewCount by one. This method is used by the view, specifically, it is the call back method for the button's click event. Whenever the button is clicked, this method is called and increment the property viewCount by one.

Here is the source code of the about view which is used by AboutComponent:

<div class="row">
   <div class="col-xs-12 col-sm-offset-1 col-sm-10">
      <div class="row">
         <div class="col-xs-12">
         <h3>About This Site</h3>
         <hr>
         <p>This is an about page. This page has been viewed {{viewCount}} times.</p>
         </div>
         
         <div class="col-xs-12">
         <p>
         Click <button class="btn btn-success" (click)="incrementViewCount()">Increment</button> to increment view counts;
         </p>
         </div>
      </div>
   </div>
</div>

This is a simple view. It has two parts, the top one has the sentence of "This is an about page. This page has been viewed X times." The value X was displayed by binding with property viewCount. Model binding is done by: {{viewCount}}.

The button (named Increment) has a click event, and is bound with the method incrementViewCount() from the controller class AboutComponent. It is done with this: (click)="incrementViewCount()".

Test the Sample Application

Before you can compile and run the sample application, you must go to the src directory of this sample project. And locate the following two files:

  • systemjs.config.jstxt
  • systemjs-angular-loader.jstxt

Rename these two files to:

  • systemjs.config.js
  • systemjs-angular-loader.js

The reason I had to rename the two files and rename them back is that the js files are not permitted files going through the email server.

Once files are renamed, you can run the following command to install all the node.js packages:

npm install

Then, to run the sample application, use the following command:

npm start

Summary

That is it. In this tutorial, I have walked through all the important aspects of this simple Angular 4 sample application. My sample is a little more complicated than a simple Hello World sample application. This application has a two-page navigation. On one page, there is a simple binding of a data model in the component to the view. On the other page, there is a simple two way binding of a data model. This sample application provides me a baseline so that I can work out more complicated application.

There are many parts of this sample project which I didn't provide explanation. I don't understand some of these parts. And it didn't really matter because I didn't need to modify these parts, not yet anyways. And I believe if I take a better look at the manual on these, I should be able to understand what they does. I believe you can do the same.

There is one thing that really bothered me. I was not able to run this sample application outside tnpm lite server. I believe there uis a way. I need to configure webpack and use it as part of the build process. I should be able to package all the necessary JavaScript code into a small package and can be added into a ASP.NET application or a Java WAR file. I don't know how to accomplish this. It is something I will work on later. I think it is a solvable.

Anyways, I hope you've enjoyed this tutorial. Good luck to you learning Anugular 4.

History

09/11/2017 - First Draft.

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Hanbo
Team Leader
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

 
QuestionAngular JS Pin
Member 1340985014-Sep-17 2:18
memberMember 1340985014-Sep-17 2:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170915.1 | Last Updated 13 Sep 2017
Article Copyright 2017 by Hanbo
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid