Angular2_part2
Angular2_part2
Angular finds and calls methods like ngOnInit(), with or without the
interfaces like onInit.
lifecycle.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
@Component({
selector: 'st-lifecycle',
template: `<h1>Life Cycle Hooks</h1>`, })
export class LifeCycleComponent implements OnInit, OnDestroy {
ngOnInit() {
console.log("Component Initialized!");
}
ngOnDestroy() {
console.log("Component Destoryed!");
}
}
Dependency Injection
It is a coding pattern in which a class receives its dependencies from
external sources rather than creating them itself.
Decorators @Component, @Directive and @Pipe are subtypes
of @Injectable().
The @Injectable() decorator identifies a class as a target for
instantiation by an injector.
Angular creates an application-wide injector for you during the
bootstrap process.
You do have to configure the injector by registering the providers that
create the services the application requires.
At runtime, injectors can read class metadata in the transpiled JavaScript
code and use the constructor parameter type information to determine
what things to inject.
You can either register a provider within an NgModule or in application
components using providers property, which is an array.
Dependency injection is a way to supply a new instance of a class
with the fully-formed dependencies it requires.
Components get access services they need through
dependency injection.
An injector contains instances of services. It injects them into
other services and components as and where they are needed.
Services
Providers Property
A service is to be registered before it is used.
A service provider with the injector, or it won't know how to create the
service.
The providers property of @Component or @NgModule decorators is
used to list services to be registered with the component or module.
When a service is registered using module it is available to all
components of that module.
log.service.ts
import {Injectable} from "@angular/core";
@Injectable()
export class LogService {
log(msg:string ) : void {
console.log(msg);
}
}
uselog.component.ts
import { Component } from '@angular/core';
import { LogService} from './log.service';
@Component({
selector: 'test-log',
templateUrl : 'app/uselog.component.html',
providers : [ LogService ]
})
export class UseLogComponent {
// Injects LogService into logService property
constructor(private logService : LogService) { }
logMessage(msg : string) : void
{
this.logService.log(msg);
}
}
uselog.component.html
<html>
<head>
</head>
<body>
<h1>Using Log Service</h1> <input
type="text" #message> <button
(click)="logMessage(message.value)">Log</button>
</body>
</html>
Optional dependencies
When a service is optional, inform Angular that the dependency is optional by
annotating the constructor argument with @Optional().
@NgModule({
imports: [
BrowserModule,
HttpModule
],
})
export class AppModule {
}
Observable
Angular uses Observables to connect to backend servers.
Observable is a concept introduced in a library called
Reactive extensions.
An Observable represents an asynchronous data stream where
data arrives asynchronously.
An observer (subscriber or watcher) subscribes to an Observable.
That observer reacts to whatever item or sequence of items
the Observable emits.
Observable Operators
Observable provides set of operators where each operator performs a
single operation.
It is possible to chain result of one operator with another as most of the
operators return an Observable.
For more information about operators refer to reactivex.io.
In order to use operator, we need to import the operator as follows:
import 'rxjs/add/operator/map'; import
'rxjs/add/operator/takeLast';
Http class
Http class is used to make AJAX calls using methods like get(), post(),
delete() and put().
In order to use Http, we need to import it from @angular/http
Inject Http into our component using DI mechanism in Angular, i.e. as a
parameter to constructor.
Use get() method of Http class and provide URL of the endpoint.
Return type of get() is Observable<Response>
Client should consume the value coming from Observable by
subscribing to Observable.
It is possible to perform operations on Observable using operators
provided by RxJS library.
Each code file in RxJS should add the operators it needs by importing
from an RxJS library.
Response object contains data coming from server and we need to
convert into JSON using json() method.
class Http {
list-books.component.ts
import { Component } from '@angular/core';
import { OnInit } from '@angular/core';
import { Book } from './Book';
import { Http, Response } from '@angular/http'; import
'rxjs/add/operator/map';
@Component({
selector: 'st-books',
templateUrl: 'app/http/list-books.component.html'
})
export class ListBooksComponent implements OnInit { books: Book[];
constructor(private http: Http) {
}
ngOnInit() { this.http.get("/app/http/books.json")
.map(resp => resp.json()) // convert to JSON
.subscribe( resp => this.books = <Book[]> resp);
}
}
List-books.component.html
<html>
<head>
<title>Books</title>
</head>
<body>
<h1>Books</h1>
<table border="1" style="width:100%"> <tr>
<th>Title </th>
<th>Author </th>
<th>Price </th>
</tr>
<tr *ngFor="let b of books"> <td> {{ b.title
}} </td> <td> {{ b.author }} </td> <td>
{{ b.price }} </td>
</tr>
</table>
</body>
</html>
Forms
An Angular form coordinates a set of data-bound user controls, tracks
changes, validates input, and presents errors.
Angular support two types of forms – Template-driven Forms and
Reactive (model-driven) forms.
Template-driven Forms
We build forms by creating templates using Angular template syntax
with form-specific directives.
Create properties that are to be bound to controls in the form.
Use two-way data binding with ngModel directive.
In the application root module import FormsModule from
@angular/forms.
List FormsModule in imports array of the module
Angular automatically creates and attaches an NgForm directive to
the <form> tag.
The NgForm directive supplements the form element with additional
features. It holds the controls you created for the elements with
an ngModel directive and name attribute, and monitors their
properties, including their validity. It also has its own valid property
which is true only if every contained control is valid.
Internally, Angular creates FormControl instances and registers them
with an NgForm directive that Angular attached to the <form> tag. Each
FormControl is registered under the name you assigned to
the name attribute.
The NgModel directive doesn't just track state; it updates the control with
special Angular CSS classes that reflect the state. You can leverage those
class names to change the appearance of the control.
You can access classes associated with a form control using its template
reference variable.
<input type="text" id="name" required
[(ngModel)]="cust.name" name="name" #spy>
<br>{{spy.className}}
Submitting form
Use ngSubmit directive to take action when form is submitted with a submit
button.
customer.component.ts
import { Component } from '@angular/core'; import {
Customer } from './Customer';
@Component({
selector: 'customer',
templateUrl: './app/customer.component.html' })
export class CustomerComponent { model = new
Customer(1,"","",""); submitted = false;
resetForm()
{
this.model = new Customer(1,"","","");
this.submitted = false;
}
customer.component.html
<html>
<body>
<h1>Customer</h1>
<form (ngSubmit)="onSubmit()" #custForm="ngForm"> Name <br>
<input type="text" id="name" [(ngModel)]="model.name"
name="name" required #name="ngModel">
<span [hidden]="name.valid || name.pristine">Name is
required!</span>
<p></p>
Email<br>
<input type="text" id="email" [(ngModel)]="model.email"
name="email">
<p></p>
<button type="submit"
[disabled]="!custForm.form.valid">Submit</button>
<button type="reset" (click)="resetForm()"
*ngIf="submitted">Reset</button>
</form></body></html>
FormGroup
A FormGroup aggregates the values of each child FormControl into one
object, with each control name as the key.
It calculates its status by reducing the statuses of its children. For
example, if one of the controls in a group is invalid, the entire group
becomes invalid.
FormGroup provides methods using which we can get or set values to
FormControls.
getRawValue() : any
Note: But unlike setValue, patchValue cannot check for missing control
values and does not throw helpful errors.
Each FormControl has the following properties.
Property Description
myControl.value Value of a FormControl.
myControl.status Validity of a FormControl. Possible
values: VALID, INVALID, PENDING, or DISABLED.
myControl.pristine True if the user has not changed the value in the
UI. Its opposite is myControl.dirty.
myControl.untouched True if the control user has not yet entered the
HTML control and triggered its blur event. Its
opposite is myControl.touched.
FormBuilder
This provides a factory method to create FormGroup. It is easier to create a
set of controls in single object rather than creating individual FormControl
objects.
register.component.ts
import { Component } from '@angular/core';
import { FormControl, FormGroup, FormBuilder, Validators} from
'@angular/forms';
@Component({
selector: 'st-register',
templateUrl: '/app/reactive/register.component.html' })
export class RegisterComponent {
/* -- We can create a FormGroup in this way also registerForm =
new FormGroup ({
email : new FormControl("[email protected]"), mobile : new
FormControl("9059057000")
});
*/
registerForm : FormGroup;
constructor (private fb: FormBuilder ) {
this.registerForm = this.fb.group(
{
email : ["", Validators.required], mobile :
["",Validators.required]
}
)
}
onSave(): void{
console.log( this.registerForm); this.registerForm.setValue( {
"email" : ""});
}
}
register.component.html
<h2>Registraion</h2>
<form [formGroup]="registerForm" novalidate> Email
Address <br>
<input type="text" formControlName="email" required> <p></p>
Mobile Number <br>
<input type="text" formControlName="mobile" required> <p></p>
<button (click)="onSave()"
[disabled]="!registerForm.valid">Submit </button>
<p></p>
Value : {{ registerForm.controls.email.value }} <p></p>
Pristine : {{ registerForm.controls.email.pristine }} <p></p>
Touched : {{ registerForm.controls.email.touched }} <br> {{
registerForm.get("email").value }}
</form>
Routing
Routing allows users to move from one view to another view using
different URLs in the client.
The Angular router is an external, optional Angular NgModule
called RouterModule.
The router is a combination of multiple provided services
(RouterModule), multiple directives (RouterOutlet, RouterLink,
RouterLinkActive), and a configuration (Routes).
Router can interpret a browser URL as an instruction to navigate to a
client-generated view. It can pass optional parameters along to view
component.
<base href>
In index.html place <base href> as the first child of head section. It tells the
router how to compose navigation URLs.
<base href="/">
Router imports
The Angular Router is an optional service that presents a particular
component view for a given URL. It is not part of the Angular core. It is in
its own library package, @angular/router.
Import what you need from it as you would from any other Angular
package.
We need to pass the above array to RouterModule.forRoot() to
configure the router.
Each Route maps a URL path to a component. There are no leading slashes
in the path. The router parses and builds the final URL for you, allowing
you to use both relative and absolute paths when navigating between
application views.
The :id in the second route is a token for a route parameter. In a URL
such as /details/1, "1" is the value of the id parameter.
The data property in the third route is a place to store arbitrary data
associated with this specific route. The data property is accessible within
each activated route. Use it to store items such as page titles,
breadcrumb text, and other read-only, static data.
The empty path represents the default path for the application, the
place to go when the path in the URL is empty.
The ** path in the last route is a wildcard. The router will select this route
if the requested URL doesn't match any paths for routes defined earlier in
the configuration.
The order of the routes in the configuration matters and this is by
design. The router uses a first-match wins strategy when matching
routes, so more specific routes should be placed above less specific
routes.
A redirect route requires a pathMatch property to tell the router how to
match a URL to the path of a route. Value full means the entire URL must
match the given string.
Router outlet
Given this configuration, when the browser URL for this application
becomes /list, the router matches that URL to the route path /list and
displays AuthorsListComponent after a RouterOutlet that you've placed in
the host view's HTML.
<router-outlet></router-outlet>
Router links
Most of the time you navigate as a result of some user action such as
the click of an anchor tag.
The RouterLink directives on the anchor tags give the navigation.
The RouterLinkActive directive on each anchor tag helps visually
distinguish the anchor for the currently selected "active" route. The
router adds the active CSS class to the element when the associated
RouterLink becomes active.
Router state
After the end of each successful navigation lifecycle, the router builds a
tree of ActivatedRoute objects that make up the current state of the
router. You can access the current RouterState from anywhere in the
application using the Router service and the routerState property.
Each ActivatedRoute in the RouterState provides methods to traverse
up and down the route tree to get information from parent, child and
sibling routes.
Route Parameters
Route parameters are used to pass data to a page.
Parameters are prefixed with: (colon) in URL. For example, in URL
/details/:id, id is route parameter.
We can have multiple parameters each separated with /. For
example,if we have a URL /author/:id/:subject then actual URL is
/author/10/angular.
You need to pass values to parameters using routeLink directive
as shown below:
<a [routerLink]="['/details',author.id]">
{{author.name}}</a>
id = this.route.snapshot.params["id"];
Router Meaning
Part
Router Displays the application component for the active URL.
Manages navigation from one component to the next.
RouterModul
e A separate Angular module that provides the necessary
service providers and directives for navigating through
application views.
Routes Defines an array of Routes, each mapping a URL path to a
component.
Route Defines how the router should navigate to a component
based on a URL pattern. Most routes consist of a path and a
component type.
RouterOutlet The directive (<router-outlet>) that marks where the router
displays a view.
this.router.navigate( ['list'])
app/routing/Author.ts
export class Author { constructor(
public id: number,
public name: string,
public email: string,
public imageUrl: string) { }
app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import {
RouterModule, Routes } from '@angular/router'; import {
AuthorsListComponent } from './routing/authors-list.component';
import { AuthorDetailsComponent } from './routing/author-
details.component';
import { MainComponent } from './routing/main.component'; import {
HomeComponent } from './routing/home.component'; const appRoutes:
Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'list', component: AuthorsListComponent }, { path:
'details/:id', component:
AuthorDetailsComponent },
{ path: '', component : HomeComponent}, { path:
'**', component: HomeComponent }
];
@NgModule({
imports: [RouterModule.forRoot(appRoutes),
BrowserModule, FormsModule,HttpModule],
declarations: [HomeComponent, AuthorDetailsComponent,
AuthorsListComponent, MainComponent],
bootstrap: [MainComponent]
})
export class AppModule { }
app/routing/main.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'authors',
templateUrl: 'app/routing/main.component.html' })
export class MainComponent {
<html>
<body>
<h2>Authors</h2>
[<a routerLink="/home"
routerLinkActive="active">Home</a>]
[<a routerLink="/list" routerLinkActive="active">List Authors</a>]
<p></p> <router-outlet></router-outlet>
</body>
</html>
app/routing/home.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'authors',
template :`<h2>About Authors </h2>
This application show details of Authors.`
})
export class HomeComponent {
}
app/routing/authors-list.component.ts
import { Component } from '@angular/core'; import
{ Author } from "./Author"; @Component({
selector: 'authors-list',
templateUrl : 'app/routing/authors-list.component.html' })
export class AuthorsListComponent { authors
: Author [] ; ngOnInit() {
this.authors = Author.getAuthors();
}
}
App/routing/authors-list.component.html
<html>
<body>
<h2>Authors</h2>
<ul>
<li *ngFor="let author of authors">
<a [routerLink]="['/details', author.id]">
{{author.name}} </a>
</li>
</ul>
</body>
</html>
App/routing/author-details.component.ts
import { Component, Input } from '@angular/core'; import {
Author } from './Author';
import { ActivatedRoute, Params, Router } from
'@angular/router';
@Component({
selector: 'author-details',
templateUrl: 'app/routing/author-details.component.html' })
export class AuthorDetailsComponent { author:
Author;
id : number;
ngOnInit(): void {
this.id = this.route.snapshot.params["id"]; this.author =
this.getAuthor(this.id);
}
getAuthor(id : number) : Author
{
for (var a of Author.getAuthors()) { if (a.id == id)
{
return a;
}
}
}
back() {
this.router.navigate( ['list']);
}
}
App/routing/author-details.component.html
<div *ngIf="author">
<h2>{{author.name}}</h2>
<h3>{{author.email}}</h3>
<img [src]="'/app/routing/' + author.imageUrl"> </div>
<button (click)="back()">Back</button>