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;