Introduction to Angular 2

Angular 2 is a client-side framework to build web applications. It is very flexible in terms of being used with both mobile and web platforms. The basic advantage of using Angular is that it follows the ECMAScript 6 standard and developers can do object-oriented programming, define classes and interfaces, implement classes, and define data structures using Plain Old JavaScript Objects (POJO) for binding data. Another big advantage in terms of performance is the unidirectional data flow. Unlike Angular 1.x, Angular 2 provides both the option of doing two-way data binding or unidirectional data binding. In certain cases, unidirectional binding is good for performance. For example, when submitting a form, two way bindings with controls may be overkill.

Angular 2 architecture

Angular2 consist of a number of components. Each component can be bound to the page by either a selector, for example <my-app> </my-app>, or a routing module. Each component has a selector, template HTML or template reference link, directives, providers, and a controller class whose properties and methods can be accessed in the associated view. When the web application first starts, System.import loads the main component of the application, which bootstraps the root component. Here is a sample main component bootstrapping an Angular app:

//Loading module through Import statement
Import {AppComponent} from 'path of my component'
bootstrap(AppComponent, [Providers]);

Providers can be defined inside square brackets. There are various providers available, which we will discuss in a later chapter.

This bootstrap object is in angular2/platform/browser, which can be imported into the TypeScript file with the import command:

import {bootstrap} from 'angular2/platform/browser';

This bootstrap object directs Angular to load the component defined in it. When the component is loaded, all the attributes or metadata defined for the component are evaluated. Each component should have the @Component annotation, some properties to define metadata about the component, and one or more classes termed as component controllers that contain properties and methods accessible by the template defined in the @Component template or templateUri properties.

Here is a sample app.component.ts that contains a selector, a template, and a class, AppComponent:

//app.component.ts
import { Component, View} from 'angular2/core';
  import {bootstrap} from 'angular2/platform/browser';
  @Component({
  selector: "my-app",
  template: `<p>This is a first component</p>`,
  })  
  class AppComponent  {
  }
  bootstrap(AppComponent);

Events of component life cycle

When the component initializes, it goes through several events and has a very structured life cycle process. We can implement these events to do specific operations. The following table shows the list of events we can use in our component controller class:

Event

Description

ngOnInit()

It is called after the component is initialized and the controller constructor is executed.

ngOnDestroy()

It is used to clean up resources when the component is disposed of.

ngDoCheck()

It is used to override the default change detection algorithm for a directive.

ngOnChanges(changes)

It is invoked when any of the component selector property values get modified. (Custom properties of the selectors can be defined through inputs.)

ngAfterContentInit()

It is invoked when the directive's content is initialized. (Directives are defined later.)

ngAfterContentChecked()

It is invoked every time the directive's content is checked.

ngAfterViewInit()

It is invoked when the view is completely initialized.

ngAfterViewChecked()

It is invoked on every check of your component's view.

Modules

A module represents a container that contains classes, interfaces, and more, to export functionality, so other modules can be imported using the import statement. For example, here is math.ts, used to perform different arithmetic operations:

//math.ts
import {Component} from 'angular2/core';
@Component({
  
})
export class MathService {
  constructor() {
  }
  public sum(a: number, b: number): number {
  return a + b;
  }
  public subtract(a: number, b: number): number {
  return a - b;
  }
  public divide(a: number, b: number): number {
  return a / b;
  }
  public multiply(a: number, b: number): number {
  return a * b;
  }
}

Components

A component is a combination of the @Component annotation to define metadata properties and the associated controller class that contains the actual code, such as the class constructor, methods, and properties. The @Component annotation contains the following metadata properties:

@Component({
  providers: string[],
  selector: string,
  inputs: string[],
  outputs: string[],
  properties: string[],
  events: string[],
  host: { [key: string]: string },
  exportAs: string,
  moduleId: string,
  viewProviders: any[],
  queries: { [key: string]: any },
  changeDetection: ChangeDetectionStrategy,
  templateUrl: string,
  template: string,
  styleUrls: string[],
  styles: string[],
  directives: Array < Type | any[] >,
  pipes: Array < Type | any[] >,
  encapsulation: ViewEncapsulation
})

Core properties of Angular 2 components

When defining a component, we can specify various properties, as listed previously. Here we will see some of the core properties that are often required when creating Angular 2 components:

  • Templates and selectors
  • Inputs and outputs
  • Directives
  • Providers

Templates and selectors

The following real example contains the template and the selector defined in the component class. When the button is clicked, it will call the logMessage() method, which prints the message in the <p> element. If you notice, we have not used the export keyword with the class because we have already bootstrapped the component on the same file and this component does not need to be referenced anywhere else:

import { Component, View } from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
@Component({
  selector: "my-app",
  template: "<p> {{message}}</p><button (click)='logMessage()'>Log Message</button>"
})
class AppComponent {
  logMessage() {
    this.message = "Hello World";
  }
  message: string = "";
}
bootstrap(AppComponent);

The app selector can be used anywhere in the HTML or index.cshtml page if working on an ASP.NET project, and the template will be rendered inside it. Here is an example of using the custom tag my-app:

<html>
<body>
  <my-app></my-app>
</body>
</html>

Once the page runs, it will render the output with this generated source:

<html>
<body>
  <p>Hello World</p>
  <button (click)='logMessage()'>Log Message</button>
</body>
</html>

Inputs and outputs

Inputs allow developers to specify the custom attributes mapped to some property of the component class downward in the hierarchy of components, whereas outputs are used to define custom event handlers on the component that can be raised upward in the hierarchy of components. In short, inputs are used to send data from parent to child components, whereas outputs are used to invoke events from child to parent components. In the previous example, we saw how selectors can be used, and the associated template is rendered in place of a selector, with the provision of having all the members of the component class available. In certain cases, we have to specify some attributes in our custom selector to pass the value to handle particular actions. For example, we may need some attribute in the previous <my-app> tag to specify the logging type, such as to log on to a developer's console or show an alert message.

Using inputs

In this example, we will create two input attributes, logToConsole and showAlert. We can define input attributes in the @Component annotation. The following code snippet is the separate component defined in child.component.ts and contains the selector as child; the template displays the Boolean values of the logToConsole and showAlert attributes specified in the child tag. The inputs contain the list of string variables that will be defined as the child tag attributes:

//child.component.ts
import { Component} from 'angular2/core';
@Component({
  selector: 'child',
  template: `<div> Log to Console: {{logToConsole}}, Show Alert: {{showAlert}} <button (click)="logMessage()" >Log</button> </div>`,
  inputs: ['logToConsole', 'showAlert'],
})

Here is the ChildComponent class that contains the logToConsole and showAlert Boolean variables. These variables actually hold the values supplied from the notification tag. Finally, we have the logMessage() method that will be invoked on a button click event and either log the message on the developer's console or show an alert message based on the value that has been set by the parent component in the hierarchy:

export class ChildComponent {
  public logToConsole: boolean;
  public showAlert: boolean;

  logMessage(message: string) {
    if (this.logToConsole) {
      console.log("Console logging is enabled");
    }
    if (this.showAlert) {
      alert("Showing alert message is enabled");
    }
    
  }
}

In the app.component.ts file, where we have the main AppComponent defined, we can use the child selector as shown in the following code. When defining the child selector, we can set the values for custom inputs defined in the ChildComponent, logToConsole and showAlert. This way the parent component can specify the values to the child component through inputs. Here is the complete code of AppComponent:

//app.component.ts
import { Component, View } from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {ChildComponent} from './child.component';

@Component({
  selector: "my-app",
  template: `<child [logToConsole]=true [showAlert]=true></child>`,
  directives: [ChildComponent]
})
export class AppComponent {
}
bootstrap(AppComponent);

Tip

When using template to define HTML, we can use a backtick (`) rather than the double quotes ('') or single quotes ('), as shown the preceding example. This allows the HTML content to span multiple lines.

Using outputs

Outputs are used to invoke events on the parent component from child components in the hierarchy of components. We will modify the preceding example and add the outputs event in the ChildComponent, then register it in the AppComponent using the ChildComponent selector.

Here is the modified code snippet for ChildComponent:

  //child.component.ts
import { Component, EventEmitter, Output} from 'angular2/core';
@Component({
  selector: 'child',
  template: `<div> Log to Console: {{logToConsole}}, Show Alert: {{showAlert}}  <button (click)="logMessage()" >Log</button> </div>`,
  inputs: ['logToConsole', 'showAlert']
})
export class ChildComponent {
  public logToConsole: boolean;
  public showAlert: boolean;
  @Output() clickLogButton = new EventEmitter();
  
  logMessage(message: string) {
    this.clickLogButton.next("From child");
  }
}

The @Output property lists clickLogButton as a custom event that ChildComponent can emit, which its parent AppComponent will receive.

We have added EventEmitter in the import statement. EventEmitter is a built-in class that ships with Angular and provides methods for defining and firing custom events. Once the logMessage() method is executed, it will execute the clickLogButton.next() method from the ChildComponent, which finally calls the event registered in the AppComponent.

We have added the clickLogButton in the AppComponent, as shown in the following code. In Angular 2, we can specify the event by specifying the event name in brackets () followed by the method that will be called when the event is raised. This is how the event is registered. Here, logMessage is the local method defined in the AppComponent:

(clickLogButton)="logMessage($event)"

Here is the code snippet for AppComponent:

  //app.component.ts 
import { Component, View } from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {ChildComponent} from './child.component';

@Component({
  selector: "my-app",
  template: `<child [logToConsole]=true [showAlert]=true (clickLogButton)="logMessage($event)" ></child>`,
  directives: [ChildComponent]
})
export class AppComponent {

  logMessage(value) {
    alert(value);
  }
}
bootstrap(AppComponent);

The logMessage method is the method that will be invoked when the event is raised from the ChildComponent.

Directives

Directives are custom tags that render the HTML at runtime but encapsulate the rendering content in the directive itself. We can relate it to the tag helpers in ASP.NET. There are three kinds of directives, components, structural directives, and attribute directives:

  • Components: It is a directive with a template.
  • Structural directive: It is a directive to add or remove DOM elements. There are some built-in structural directives that Angular provides. Directives such as ngIf, ngSwitch, and ngFor are structural directives.
  • Attribute directive: It changes the appearance of any DOM element.

Creating a simple Hello World directive

Directives can be created in a simple way, as a component is created, and can be referenced in the calling component through its selector tag.

Here is an example of HelloWorldComponent that defines a simple directive to display a "Hello world" message in the heading format:

//helloworld.component.ts
import {Component} from 'angular2/core';

@Component({
  selector: "helloworld",
  template: "<h1>Hello world</h1>"
})

export class HelloWorldComponent {
  
}

The following example is the component that uses this directive. When using any directive, it has to be first imported through the import statement, then the @Component metadata property needs to be set to access it in the associated template:

import { Component, View, provide, Inject } from 'angular2/core';
  import {bootstrap} from 'angular2/platform/browser';
  import {HelloWorldComponent} from './helloworld.component';

  @Component({
    selector: "my-app",
    template: `<helloworld></helloworld>`,
    directives: [, HelloWorldComponent],
  })
  export class AppComponent{
 
  }
  bootstrap(AppComponent);

This directive can be used on the page as follows:

<helloworld></helloworld>

Structural directives

Structural directives can be used to add or remove DOM elements. For example, we can add the list of countries as a table through *ngFor, as shown in the following code, and hide or unhide the div through the *ngIf directive:

  <div *ngIf="display">
    <table>
      <thead>
        <tr>
          <th>
            Country
          </th>
          <th>
            Currency
          </th>
        </tr>
      </thead>
      <tbody *ngFor="#country of countries">
        <tr><td>{{country.CountryName}}</td><td>{{country.Currency}}</td></tr>
      </tbody>
    </table>
  </div>

Here is the backend countries.component.ts, which uses the HTTP module to call the ASP.NET Web API service. It returns a list of countries, which is assigned to the countries array. The display default value is set to true, which generates the table. By setting the display value to false, the table will not be generated:

///<reference path="../../node_modules/angular2/typings/browser.d.ts" />
import {Component} from 'angular2/core';
import {Http, Response} from 'angular2/http';

@Component({
  selector: 'app',
  templateUrl: 'Countries'
})
export class TodoAppComponent {
  countries = [];
  display: boolean = true;
  //constructor
  constructor(private http: Http) {
  }

  //Page Initialized Event Handler
  ngOnInit() {
    this.getCountries();
  }
  getCountries() {
    this.http.get("http://localhost:5000/api/todo").map((res: Response) => res.json())
      .subscribe(data => {
        this.countries = data;
      },
      err => console.log(err),
      () => console.log("done")
      );
  }

}

This is how structural directives can be used in Angular 2. In the following chapter, we develop a sample application and discuss each artifact for making HTTP GET and POST requests using Angular 2.

Attribute directive

An attribute directive requires building a controller class annotated with @Directive and defines a selector to identify the attribute associated with it. In the following example, we will develop a simple myFont directive that changes the text to italic when it is applied to any page elements. Here is the font.directive.ts file:

import { Directive, ElementRef, Input } from 'angular2/core';
@Directive({ selector: '[myFont]' })
export class FontDirective {
  constructor(el: ElementRef) {
    el.nativeElement.style.fontStyle = 'italic';
  }
}

For each matching element on the page, Angular creates a new instance and injects ElementRef into the constructor. ElementRef is a service through which we can directly access the element through its nativeElement property and access other attributes. In the preceding code snippet, we are changing the font style to italic for the elements that have the myFont directive applied.

On the page level, it can be used as follows:

<p myFont>myFont is an Attribute directive</p>

Providers

Providers are used to register the types that gets instantiated through the dependency injection framework of Angular 2. When a component is initialized, Angular creates a dependency injector which registers all the types specified in the providers array. Then at the constructor level, if there is any type defined in the providers array, it will get initialized and injected into the constructor.

The following example is MathComponent, which will be injected into the main app component constructor and call the sum method to add two numbers together:

//math.component.ts
import { Component } from 'angular2/core';
@Component({})

export class MathComponent {
  
  public sum(a: number, b: number) : number{
    return a + b;
  }
  public divide(a: number, b: number): number {
    return a / b;
  }
  public subtract(a: number, b: number): number {
    return a - b;
  }
  public multiply(a: number, b: number): number {
    return a * b;
  }

}

The following example is AppComponent, showing how to import a math component, then defining the provider and injecting it at the constructor level:

//app.component.ts
import { Component, View } from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {MathComponent} from './servicemanager.component';
  @Component({
    selector: "my-app",
    template: "<button (click)="add()" >Log</button>",
    providers: [MathComponent]
  })  
  export class AppComponent  {
    obj: MathComponent;
    constructor(mathComponent: MathComponent) {
      this.obj = mathComponent;
    }
    public add() {
      console.log(this.obj.sum(1, 2));
    }
  }
  bootstrap(AppComponent);

Other primitive types can also be injected in a slightly different way using the Inject Angular module. We can also define a type using the provide keyword, which takes a key and the value:

providers: [provide('Key', {useValue: 'Hello World'})]

The preceding syntax can also be used when defining types in providers, as follows:

providers: [provide(MathComponent, {mathComponent: MathComponent })]

One of the main benefits of defining providers with the provide keyword is when testing. When testing applications, we can replace the actual components with the mock or test components. For example, suppose we have a class that calls some SMS service to send SMS using some paid gateway, and in the testing cycle we don't want to use the production SMS gateway component, but rather we would like to have some custom test component that just inserts the SMS into a local database. In this case, we can associate some mock class, such as SMSTestComponent, to perform testing scenarios.

The following example injects the string value into the constructor. We need to add the Inject module as specified in the following code, and then use @Inject to inject the value associated to the key:

  //app.component.ts
import { Component, View, provide, Inject } from 'angular2/core';
  import {bootstrap} from 'angular2/platform/browser';
  import {MathComponent} from './servicemanager.component';
  @Component({
    selector: "my-app",
    template: `button (click)="logMessage()" >Log</button>`,
    providers: [MathComponent, provide('SampleText', {useValue: 'Sample Value'})]
  })
  export class AppComponent{
    obj: MathComponent;
    Val: string;
    constructor(mathComponent: MathComponent, @Inject('SampleText') value) {
      this.obj = mathComponent;
      this.Val = value;
    }
      
  public logMessage() {
    alert(this.kVal);
  }
  }
  bootstrap(AppComponent);

Dependency injection in Angular

Angular chains dependency injection and injects components into the child components if they are defined in the providers array of the parent component. However, a child component can define the same component in its own providers array. The scope of the component travels through the chain of components. However, components that are defined in the viewproviders array aren't injected or inherited by the child components in the hierarchical chain.

Let's take a simple example that contains one main component in app.ts and AppComponent defines two providers: ChildComponent and MathComponent. ChildComponent is the child of the parent component, whereas MathComponent is used in both the parent and child components. If you notice, in the following code snippet, we have not specified the MathComponent in the providers array of the ChildComponent, and as it is defined in the ParentComponent, it is already injected by the Angular dependency injection module.

Here is the code snippet for AppComponent (parent):

  //app.component.ts
  import { Component} from 'angular2/core';
  import {bootstrap} from 'angular2/platform/browser';
  import {MathComponent} from './servicemanager.component';
  import {ChildComponent} from './child.component';
  @Component({
    selector: "my-app",
    template: `<button (click)="callChildComponentMethod()">Log</button>`,
    providers: [MathComponent, ChildComponent]
  })
  export class AppComponent  {
    childObj: ChildComponent;
      constructor(childComponent: ChildComponent) {
      this.childObj = childComponent;
  
  }
    public callChildComponentMethod() {
      this.childObj.addNumbers(1, 2);   
      
    }
  }
  bootstrap(AppComponent);

The following is the code snippet for MathComponent, which contains some basic arithmetic operations:

//math.component.ts
import { Component } from 'angular2/core';
@Component({})
export class MathComponent {
  
  public sum(a: number, b: number) : number{
    return a + b;
  }
  public divide(a: number, b: number): number {
    return a / b;
  }
  public subtract(a: number, b: number): number {
    return a - b;
  }
  public multiply(a: number, b: number): number {
    return a * b;
  }
}

Finally, here is the ChildComponent code, which does not have the MathComponent provider defined in the providers array:

//child.component.ts
import {Component} from 'angular2/core';
import {MathComponent} from './servicemanager.component';
@Component({
  selector: 'child-app',
  template: '<h1>Hello World</h1>'
})
export class ChildComponent {
  obj: MathComponent;
  constructor(mathComponent: MathComponent) {
    this.obj = mathComponent;
  } 
  public addNumbers(a: number, b: number) {
    alert(this.obj.sum(a, b));
  }
}

Routing in Angular

Routing has an essential role when working with large applications. Routing is used to navigate to different pages. Routing can be defined in three steps:

  1. Define @RouteConfig at any component level:
    @RouteConfig([
      { path: '/page1', name: 'Page1', component: Page1Component, useAsDefault: true },
      { path: '/page2', name: 'Page2', component: Page2Component }]
    )
  2. Use the [routerLink] attribute on the anchor HTML tag and specify the route name configured in @RouteConfig.
  3. Finally, add the <router-outlet> tag to render the page on the current navigated route.

The following example contains two components, Page1Component and Page2Component, and the main AppComponent has routing defined like this:

//app.component.ts
import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {Page1Component} from './page1.component';
import {Page2Component} from './page2.component';

@Component({
  selector: "my-app",
  template: `{{name}}
    <a [routerLink]="['Page2']">Page 2</a>
    <router-outlet></router-outlet>`,
  directives: [ROUTER_DIRECTIVES],
})
@RouteConfig([
  { path: '/', name: 'Page1', component: Page1Component, useAsDefault:true },
  { path: '/page2', name: 'Page2', component: Page2Component }]
)
export class AppComponent {
}

In the preceding code, first we imported the RouteConfig and ROUTER_DIRECTIVES from angular2/router and then defined the RouteConfig for page 1 and page 2. In the inline template, we placed the anchor tag and defined the route name for page 2. When the application runs, page 1 is set as a default page on a root path /, so the page 1 content will be displayed in place of the router outlet. When the user clicks on the Page2 link, the page 2 content will be rendered in the same place.

Here is the code of page1.component.ts:

//page1.component.ts
import {Component} from 'angular2/core';
@Component({
  template:'<h1>Page1 Content</h1>'
})
export class Page1Component {
}

Here is the code of page2.component.ts:

//page2.component.ts
import {Component} from 'angular2/core';

@Component({
  template: '<h1>Page2 Content</h1>'
})

export class Page2Component {
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.166.99