Angular 2+ components (practical reference)

The basic unit of any Angular Application is the component

This post summaries the common tasks with components and can be used as a pool of useful code snippets

  • Creating
  • Data binding – one way and 2-way
  • Using ngIf and ngFor to create dynamic template content
  • creating and communicating with nested components

Creating a new Angular App

# ng new CompTests
# cd CompTests
# ng serve

The generated a simple app with one main component and one module:

  • app.module.ts – the main module class
  • app.component.ts – the parent component code
  • app.component.html – the parent component template
  • app.component.css – the parent component styles

Integrating Twitter bootstrap

# npm install bootstrap --save

now open the file .angular-cli.json (in the project root directory) and add the bootstrap css to the styles section:

"styles": [
  "styles.css",
  "../node_modules/bootstrap/dist/css/bootstrap.css"
],

restart the web server to see the result (Ctrl + c , ng serve)

Adding Forms Module

To use forms components you need to import the Forms Module, add the following code to the main app module (app.module.ts)

import {FormsModule} from "@angular/forms";

imports: [
  BrowserModule,
  FormsModule,
  …

DataBinding

One way – from code to template

Interpolation – code:

num:number = 10;

template:

{{ num }} , {{ num*10 }}

 

Property binding – code:

num1:number = 100;
col:string = “red”;
sz:number = 20;

template:

<input [value]=’num1’ />
<label [style.color]="col" [style.font-size.px]="sz">Hi</label>

Note that the following 2 ways have the same results:

<input [value]=’num1’ />
<input value={{num1}} />

 

One way – from the template to the code

Events and event handlers

Button click event

<button (click)=”f1()”>click</button>

Code:

f1(){
	console.log(‘button click’);
}

 

Input key event

<input (keypress)=”f2()”/>

you can send the event object using $event:

<input (keypress)=”f2($event)”/>

Code:

f2(ev){
	console.log(‘key press’ + ev.key);
}

you can send any data you like – for example calculator buttons calling the same event with different values:

<button (click)="cl(1)">1</button>
<button (click)="cl(2)">2</button>
…
<button (click)="cl(9)">9</button>

 

2-way data-binding

textbox

<input [(ngModel)]=’num2’ />

Code:

num2:numer = 90;

 

Checkbox

<input type="checkbox" [(ngModel)]="bl" value="Checkbox">

Code:

bl:boolean;

 

select

<select [(ngModel)]="Item">
  <option *ngFor="let item of Items"
          [value]="item.id">
    {{item.name}}
  </option>
</select>

Code:

export interface Item {
   id: number;
   name: string;
}

// in the component class code:
Item: number;

Items: Item[] = [
  {
    name : 'liran',
    id: 100
  },
  {
    name : 'avi',
    id: 200
  },
  {
    name : 'dani',
    id: 300
  },
];

 

Built in directives

If Statement

<div *ngIf="num3 % 2 == 0">{{num3}}</div>

displays the content of num3 if the condition is true, otherwise displays nothing

 

if-else

<div *ngIf="num2 % 2 == 0; else errmsg">
  Condition is true!
</div>
<ng-template #errmsg>
  Condition is false!
</ng-template>

 

2 templates

<div *ngIf="cond ; then tmpl1 else tmpl2"></div>

<ng-template #tmpl1>
  Correct!
</ng-template>

<ng-template #tmpl2>
  Wrong!
</ng-template>

 

For Statement

  • Create a list of template elements
  • Put the ngFor on the element you want to duplicate
  • Iterate over a data structure (array or any collection)

Code:

items: string[] = ['avi','dani','yosi'];

template:

<ul *ngFor="let item of items">
  <li>{{item}}</li>
</ul>

Add index to each item:

<ul *ngFor="let item of items; let i = index" [attr.data-index]="i">
  <li>{{item}}</li>
</ul>

Simple loop, fixed size

<ul>
  <li *ngFor="let number of [0,1,2,3,4]">{{number}}</li>
</ul>

Simple Loop, dynamic size

constructor() {  
         let size=10;               
         this.ar = Array(size).fill(0).map((x,i)=>i); 
}
ar:number[];

Template:

<li *ngFor="let number of ar">{{number}}</li>

 

Table with ngIf and ngFor

Displays the table only if the array is not null and contains elements

<table border='1' width='100%' *ngIf='books && books.length > 0'>
   <tbody>
      <tr *ngFor='let b of books'>
        <td> {{b.Id}} </td>
        <td> {{b.Name}} </td>
        <td> {{b.Price }} </td>
        <td> {{b.Rate}} </td>
      </tr>
   </tbody>
</table>

ngStyle

code:

style1 =  {
  'color': 'green',
  'font-size': 20
}

Template:

<label [ngStyle]="style1">Bye</label>

 

ngClass

<label [ngClass]="'s1'">Hi</label>

In the CSS file (or inline style)

.s1 {
  color: red;
  font-size: 30px;
}

 

Nested components

 

Creating a new component:

# ng g c Comp2

using inline style and template:

# ng g c --it --is Comp3

Creating the new file(s) in the same directory

# ng g c --flat Comp4

 

Input parameter

In the child component add:

@Input() name:string ;

bind the variable to a template item

In the parent component declare a child using the child selector and send the value

<app-comp2 [name]="n1"></app-comp2>

Or:

<app-comp2 name="{{n1}}"></app-comp2>

ng-content

You can add any element between the child tags and use it in the child component using <ng-content>

Parent:

<app-comp2 [name]="n1">
            <h2>some text</h2>
</app-comp2>

child:

<p>
            Child component
</p>
<ng-content></ng-content>

 

Output parameter (event from child to parent)

Child – Declare output variable

@Output() bclick = new EventEmitter<number>();

somewhere in the child code raise the event to the parent:

this.bclick.emit(100);

Parent

<app-comp2 (bclick)="bc($event)" >

 

2-way databinding

 

This syntax

<input type="text" [(ngModel)]="num" />

is equal to:

<input type="text" [ngModel]="num" (ngModelChange)="num = $event"/>

 

To make 2 way databinding between the parent and the child declare the following at the child component:

 

@Output() resultChange = new EventEmitter();

@Input()
set result(val) {
     this.res = val;
     this.resultChange.emit(val);
}

get result() {
 return this.res;
}

 

 

Now, in the parent component add:

<comp4 [(result)]="var1"></comp>

 

 

ViewChild

You can declare a child component object in the parent class and access its properties and methods using code for example:

Child

@Component({
  selector: 'comp3',
  template: `
    val1:<input type="text" [(ngModel)]="n1"/><br/>
    val2:<input type="text" [(ngModel)]="n2"/>
  `,
  styles: []
})

export class Comp3Component {
  n1:string = "first";
  n2:string = "last";

}

 

In the parent class declare:

@ViewChild(Comp3Component) vc:Comp3Component;

 

The above decorator attach the object to the first instance of the child component found in the template – if you have only one child, you can access it using code:

console.log(vc.n1 + “:” vc.n2);

 

ViewChildren

 

If you have more than one instance of comp3 you can declare it using:

@ViewChildren(Comp3Component) vcs: QueryList<Comp3Component>;

Now declare also

let arr = this.vcs.toArray();
alert(arr[1].num1); // accessing the second element
arr[0].num1 = 100;

 

 

 

 

 

 

 

 

 

 

Tagged