Angular Components and Modules (Running your first Angular Application)

Learn Angular Components and Angular Modules

Contents :-

What is for the next article ?

Introduction

In the previous articles we looked in to Angular prerequisites i.e. Node, TypeScript , SystemJS , Webpack and VS code. From this lab the real angular starts. In this article we will get warmed up with basic Angular syntaxes for components and modules. While doing so we will create Customer screen which we discussed in the first article.

Introduction

In this lab we will configure Angular environment and we will try to create the basic Customer screen and make it up and running. So let's start with the first step downloading angular framework and configuring typescript compiler.

Step 1:- NPM install to get Angular framework

So let's create a folder called as "Angular" and open the same using VS code. Please refer Lab 3 on how to use VS code. In case you want to Angular using visual studio you can see this video https://www.youtube.com/watch?v=oMgvi-AV-eY . If you are eclipse guy please mail me at questpond@questpond.com

So as we discussed in Lab 1 that "Node" has "npm" which helps us to get JavaScript open sources. So create a package.json file with the below details and do a "npm install" in the integrated command line of VS code.

{
  "name": "angular-quickstart",
  "version": "1.0.0",
  "license": "ISC",
  "dependencies": {
    "@angular/common": "4.0.0",
    "@angular/compiler": "4.0.0",
    "@angular/core": "4.0.0",
    "@angular/forms": "4.0.0",
    "@angular/http": "4.0.0",
    "@angular/platform-browser": "4.0.0",
    "@angular/platform-browser-dynamic": "4.0.0",
    "@angular/router": "4.0.0",
    "@angular/upgrade": "4.0.0",
    "angular-in-memory-web-api": "0.3.2",
    "bootstrap": "^3.3.6",
    "core-js": "^2.4.1",
    "http-server": "^0.10.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "^5.4.1",
    "systemjs": "0.19.27",
    "zone.js": "^0.8.4"
  },
  "devDependencies": {
    "@types/core-js": "^0.9.42",
    "typescript": "2.3.4"
  }
}

If all the npm install runs successfully you should see a node_modules folder in your VS code project directory with the following folder structure.

If you go inside the "Angular" folder you will see lot of folders like common , http , forms core and so on. Putting in simple words Angular is MODULAR.

They have developed isolated components for Forms , Http , Core and so on.

In AngularJS 1.X we just had one JS file which had the whole framework. So you drag and drop that single Angular 1.X JS file on HTML page and you are ready with the Angular 1.X environment. But the problem with having whole framework in one JS files was that you have to include all features even if you need it or not.

For instance if you are not using HTTP still that feature will be loaded. In case of Angular we have separate discrete components which makes Angular awesome.

Common errors during NPM install

This is the most crucial part of Angular. You can see that in "package.json" file we have so many dependencies and these dependencies use each other. So if one version is incompatible the whole NPM command will fail. So below are couple of things you need to take care.

First keep NPM updated to the latest version or else you can end up with a warning as shown at the side.

AND EVEN IF YOU DO NOT GET THIS WARNING STILL KEEP THE LATEST NPM VERSION.

To get the latest NPM version you need to use "npm install -g npm". This command will update NPM itself.

Also you can get the below error which shows incompatibility between modules. For example in the below figure it says "For Angular 4.0 you will need Zone.js which is greater than 0.8.4 version.

So go to your project.json , fix the version number , DELETE node_modules folder and do a NPM again.

Errors of version mismatch can be huge as shown in the below figure. Sometimes fixing "package.json" can be more painful and iterative. When you do these iterations please ensure you delete "node_modules" folder so that you are not referring old versions.

You can also get error as shown below "ERR nottarget". This error says that the particular version number is not found. Use "npm view packagename version" command to get the latest version and update your package accordingly.

Step 2:- Typescript configuration tsconfig.json

Also in the same folder we need to create tsconfig.json which defines how typescript will compile. Do not worry on what settings are there in it we will explain as we go ahead. Remember do not OVER LEARN. For now just note that the below file defines how TSC will compile.

{
  "compilerOptions": {
    "target": "es5",//defines what sort of code ts generates, es5 because it's what most browsers currently UNDERSTANDS.
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,//for angular to be able to use metadata we specify in our components.
    "experimentalDecorators": true,//angular needs decorators like @Component, @Injectable, etc.
    "removeComments": false,
    "noImplicitAny": false,
    "noStrictGenericChecks": true,
    "lib": ["es2016", "dom"]
    
  }
}

Step 3:- Configuring SystemJS module loader

\

SystemJS file defines configuration of how SystemJS will load the frameworks. So this file put it in the same folder with the name "systemjs.config.js". The name should be EXACTLY "systemjs.config.js" because systemJS looks with that name.

(function (global) {
    System.config({
        paths: {
            // paths serve as alias
            'npm:': '../node_modules/'
        },
        // map tells the System loader where to look for things
        map: {
            // our app is within the app folder
            app: 'startup',
            // angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
            'lodash':'node_modules/lodash',
            // other libraries
            'rxjs': 'npm:rxjs',
            'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
            'moment': 'npm:moment',
            // ag libraries
            'ag-grid-ng2': '../node_modules/ag-grid-ng2',
            'ag-grid': '../node_modules/ag-grid',
	'jquery': '../node_modules/jquery/dist/jquery.js',
            'ng2-auto-complete': '../node_modules/ng2-auto-complete/dist'
        },
        // packages tells the System loader how to load when no filename and/or no extension
        packages: {
            app: {
                main: '../Startup/Startup.js',
                defaultExtension: 'js'
            },
            rxjs: {
                defaultExtension: 'js'
            },
            'angular-in-memory-web-api': {
                main: './index.js',
                defaultExtension: 'js'
            },
            'lodash': { main: './index.js', defaultExtension: 'js' },
            moment: {
                defaultExtension: 'js'
            },
            'ag-grid-ng2': {
                defaultExtension: "js"
            },
            'ag-grid': {
                defaultExtension: "js"
            },
            'ng2-auto-complete': {
                main: 'ng2-auto-complete.umd.js', defaultExtension: 'js'
            }

        }
    });
})(this);

Understanding Angular Component and module architecture

As we said in the previous section that the whole goal of Angular is binding the model and the view. In Angular the binding code is officially termed as "Component". So hence forth we will use the word "Component" for the binding code.

In enterprise projects you can have lot of components. With many components it can become very difficult to handle the project. So you can group components logically in to modules.

So hence forth I will be using two terms:-

  • Components: - This will have the binding logic to bind the UI and the model.
  • Modules :- This will logically group components.

Step 4:- Following MVW Step by Step – Creating the folders

Before we start coding lets visualize the steps of coding. As we have said Angular is a binding framework. It follows MVW architecture. It binds HTML UI with the JavaScript code (model).

So if we visualize it will look something as shown in the image below. So let's move from right to left. So let's do the coding in the following sequence:-

  1. Create the model.
  2. Create the Component.
  3. Create the module.
  4. Create the HTML UI.

So let's first create four folders in our project:-

  • View folder: - This folder will contain the HTML UI.
  • Model folder: - This folder will have the main business typescript classes.
  • Component folder: - This folder will have the binding code which binds the HTML UI and Model.
  • Module: - This folder will have code which will logically group the components.

In order to create a folder in VS code you can use the "New folder" icon or you can right click and also create a folder.

Step 5:- Creating the model

A model is nothing but a class with properties and behavior. So let us first create the customer model with three properties "CustomerName", "CustomerCode" and "CustomerAmount".

So right click on the "Model" folder and add a new file "Customer.ts". Keep the extension of this file as ".ts" as it's a typescript file.

While compiling the typescript command identifies only files with the extension ".ts".

In the "Customer.ts" let's create a "Customer" class with three properties. In this book we will not be going through the basics of typescript , please do go through this 1 hour training video of typescript which explains typescript in more detail.

export class Customer {
    CustomerName: string = "";
    CustomerCode: string = "";
    CustomerAmount: number = 0;
}

Step 6:- Creating the Component

The next thing we need to code is the binding code. Binding code in Angular is represented by something termed as "COMPONENTS". Angular components has the logic which helps to bind the UI with the model.

So right click on the component folder and add "CustomerComponent.ts" file as shown in the figure at the left.

In the component we need to import two things the Angular core and our Customer model. Please note "import" is a typescript syntax and not JavaScript. So in case you are not following the code , please see this Learn Typescript in 1 hour video before moving ahead.

import {Customer} from '../Model/Customer'
import {Component} from "@angular/core"

The first line imports the "Customer" class in to the "CustomerComponent.ts". This import is only possible because we have written "export" in "Customer.ts" file. The import and export generate code which follows CommonJs , AMD or UMD specifications. In case you are new to these specifications please see this CommonJs video which explains the protocol in more detail.

import {Customer} from '../Model/Customer'

Let's try to understand how "Customer" component is located. If you see it's using a relative path. In the import it says "../Model/Customer".

The "../" says go one folder up. So we are currently in the "Component" folder , so with "../" it travels to the root and from that point it makes entry in to the "Model" folder.

The next import command imports angular core components. In this we have not given any relative path using "../" etc. So how does typescript locate the angular core components ?

import {Component} from "@angular/core"

If you remember we had used node to load Angular and node loads the JS files in the "node_modules" folder. So how does typescript compiler automatically knows that it has to load the Angular components from "node_modules" folder.
Typescript compiler uses the configuration from "tsconfig.json" file. In the configuration we have one property termed as "moduleResolution. It has two values:-

  • Classic :- In this mode typescript relies on "./" and "../" to locate folders.
  • Node :- In this mode typescript first tries to locate components in "node_modules" folder and if not found then follows the "../" convention to traverse to the folders.

In our tsconfig.json we have defined the mode as "node" this makes typescript hunt modules automatically in "node_modules" folder. That makes the "import" of Angular components work.

{
 {
  ....
  ....
    "moduleResolution": "node",
 ....
 ....
  }
}

So now that both the import statements are applied let us create the "CustomerComponent" and from that let's expose "Customer" object to the UI with the object name "CurrentCustomer".

export class CustomerComponent {
    CurrentCustomer:Customer = new Customer();
}

As we said previously that component connects / binds the model to the HTML UI. So there should be some code which tells that "CustomerComponent" is bounded with HTML UI. That's done by something termed as "Component MetaData Attribute". A component metadata attribute starts with "@Component" which has a "templateUrl" property which specifies the HTML UI with which the component class is tied up with.

@Component({
    selector: "customer-ui",
    templateUrl: "../UI/Customer.html"
})

This attribute is then decorated on the top of the component. Below goes the full code.

@Component({
    selector: "customer-ui",
    templateUrl: "../UI/Customer.html"
})
export class CustomerComponent {
    CurrentCustomer:Customer = new Customer();
}

Putting in simple words binding code is nothing but a simple typescript class which decorated by the "@Component" attribute which dictates that this typescript class is binded with which UI.

Below goes the full code of the Angular component.

// Import statements
import {Component} from "@angular/core"
import {Customer} from '../Model/Customer'

// Attribute metadata
@Component({
    selector: "customer-ui",
    templateUrl: "../UI/Customer.html"
})
// Customer component class exposing the customer model
export class CustomerComponent {
    CurrentCustomer:Customer = new Customer();
}

Step 7:- Creating the Customer HTML UI – Directives and Interpolation

Now from the "CustomerComponent" , "Customer" is exposed via the "CurrentCustomer" object to UI. So in the HTML UI we need to refer this object while binding.

In the HTML UI the object is binded by using "Directives". Directives are tags which direct how to bind with the UI.

For instance if we want to bind "CustomerName" with HTML textbox code goes something as shown below:-

  • "[(ngModel)]" is a directive which will help us send data from the object to UI and vice versa.
  • Look at the way binding is applied to the object. It's referring the property as "CurrentCustomer.CustomerName" and not just "CustomerName". Why ??. Because if you remember the object exposed from the "CustomerComponent" is "CurrentCustomer" object. So you need to qualify "CurrentCustomer.CustomerCode".
<input type="text" [(ngModel)]="CurrentCustomer.CustomerName">

  • Round brackets indicate data sent from UI to object.
  • Square brackets indicate data is sent from object to UI.
  • If both are present then it's a two way binding.

with HTML BR tag. These braces are termed as "INTERPOLATION". If you see the dictionary meaning of interpolation it means inserting something of different nature in to something else.

In the below code we are inserting object data within HTML.

{{CurrentCustomer.CustomerName}}

Below goes the full HTML UI code with binding directives and interpolation.

<div>
Name:
<input type="text" [(ngModel)]="CurrentCustomer.CustomerName"><br /><br />
Code:
<input type="text" [(ngModel)]="CurrentCustomer.CustomerCode"><br /><br />
Amount:
<input type="text" [(ngModel)]="CurrentCustomer.CustomerAmount"><br /><br />
</div>
{{CurrentCustomer.CustomerName}}<br /><br />
{{CurrentCustomer.CustomerCode}}<br /><br />
{{CurrentCustomer.CustomerAmount}}<br /><br />

Step 8:- Creating the Module

Module is a container or you can say it's a logical grouping of components and other services.

So the first import in this module is the "CustomerComponent" component.

import { CustomerComponent }   from '../Component/CustomerComponent';

We also need to import "BrowserModule" and "FormsModule" from core angular. "BrowserModule" has components by which we can write IF conditions and FOR loop. "FormsModule" provides directive functionality like "ngModel", expressions and so on.

import { BrowserModule } from '@angular/platform-browser';
import {FormsModule} from "@angular/forms"

We also need to create a typescript class "MainModuleLibrary". At this moment this class does not have any code but it can have code which will provide component level logic like caching , initialization code for those group of components and so on.

export class MainModuleLibrary { }

To create a module we need to use import "NgModule" from angular core. This helps us to define module directives.

import { NgModule }      from '@angular/core';

"NgModule" has three properties:-

  • Imports: - If this module is utilizing other modules we define the modules in this section.
  • Declarations: - In this section we define the components of the modules. For now we only have one component ‘CustomerComponent".
  • Bootstrap: - This section defines the first component which will run. For example we can have "HomeComponent", "CustomerComponent" and so on. But the first component which will run is the "HomeComponent" so that we need to define in this section.
@NgModule({
    imports: [BrowserModule,
             FormsModule],
    declarations: [CustomerComponent],
    bootstrap: [CustomerComponent]
})

Below goes the full code of Angular module which we discussed in this section.

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import {FormsModule} from "@angular/forms"
import { CustomerComponent }   from '../Component/CustomerComponent';

@NgModule({
    imports: [BrowserModule,
             FormsModule],
    declarations: [CustomerComponent],
    bootstrap: [CustomerComponent]
})
export class MainModuleLibrary { }

Step 9:- Creating the "Startup.ts" file

So we have created the UI, we have created the models, we have created components and these components are grouped in to modules. In an angular application you can have many modules.

So you need to define the startup module. So let's create a "Startup.ts" file which will define the startup module.

Below goes the "Startup.ts" file in which we have defined which module will be bootstrapped.

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { MainModuleLibrary } from '../Module/MainModuleLibrary';
const platform = platformBrowserDynamic();
platform.bootstrapModule(MainModuleLibrary);

Step 10:- Invoking "Startup.ts" file using main angular page

So let us create a startup HTML page which will invoke the "Startup.ts". Now in this page we will need to import four JavaScript framework files Shim , Zone , Meta-data and System JS as shown in the below code.


<script src="../../node_modules/core-js/client/shim.min.js"></script>
<script src="../../node_modules/zone.js/dist/zone.js"></script>
<script src="../../node_modules/reflect-metadata/Reflect.js"></script>
<script src="../../node_modules/systemjs/dist/system.src.js"></script>

Below are the use of JS files :-

Shim.min.jsThis framework ensures that ES 6 javascript can run in old browsers.
Zone.jsThis framework ensures us to treat group of Async activities as one zone.
Reflect.jsHelps us to apply meta-data on Javascript classes. We are currently using @NgModule and @NgComponent as attributes.
System.jsThis module will helps to load JS files using module protocols like commonjs , AMD or UMD.

In this HTML page we will are calling the "systemjs.config.js" file. This file will tell system JS which files to be loaded in the browser.

<script src="../systemjs.config.js"></script>
<script>
    System.config({
        "defaultJSExtensions": true
    });

    System.import('startup').catch(function (err) { console.error(err); });
</script>

In the "import" we need to specify "startup" which will invoke "startup.js" file.

System.import('startup').catch(function (err) { console.error(err); });

Our customer screen in with the name "Customer.html". So to load in to this screen we need to define a place holder. So in this place holder our Customer HTML page will load.

<customer-ui></customer-ui>

If you remember when we created the component class we had said to load the HTML page in a selector. So that selector is nothing but a tag (placeholder) to load our Customer page.

@Component({
    selector: "customer-ui",
    templateUrl: "../UI/Customer.html"
})

Below goes the full HTML page with all scripts and the place holder tag.


<!DOCTYPE html>
<html>
<head>
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
    <title></title>
	
		
	<meta charset="utf-8" />
</head>
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="../../node_modules/core-js/client/shim.min.js"></script>
<script src="../../node_modules/zone.js/dist/zone.js"></script>
<script src="../../node_modules/reflect-metadata/Reflect.js"></script>
<script src="../../node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="../systemjs.config.js"></script>
<script>
    System.config({
        "defaultJSExtensions": true
    });

    System.import('startup').catch(function (err) { console.error(err); });
</script>
<body>
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
    <customer-ui></customer-ui>

</body>


</html>

Step 11:- Setting up the typescript compiler

We also need to run typescript so that TS files gets compiled to JS files. So open the integrated terminal and type "tsc -w". This will make typescript run continuously at the background. So as you type typescript will keep compiling when the file changes.

Step 12:- Running the http-server

So if everything is ok in Step 11 we now need to now run http server.To run server we need to type "http-server" in the VS code integrated terminal as shown in the figure.

In case your 80 port is blocked you can run this server on a specific port using "http-server –p 99". This will run this server over 99 port.

 

So once the web server is running you can now browse to the main angular HTML page.
Main angular page means the page in which we have put the scripts, put the place holder , systemjs and so on.

Please note Customer.html is not the main page. This page will be loaded in the placeholder of main angular page.

Once the sites are running type in one of the textboxes and see the automation of binding output in expression.

Run in two terminals. You can open two terminals by clicking on the "+" in terminal window. So in one window you can run http-server and in other window you can run typescript in watch mode.

How to the run the source code?

The source code that is attached in this book is without "node_modules" folder. So to run the code you need to open the folder using VS code and then do a NPM using the integrated terminal on the folder where you have "package.json" file.

What is for the next article ?

In the next article we will look understand how to create Single Page applications using Angular. While doing so we will be try understand how Angular routing works.

+91-22-66752917
+91 9967590707
questpond@questpond.com / questpond@yahoo.com