@tkssharma
github.com/tkssharma

Understand event emitter Angular 5
Data flows into your component via property bindings and flows out of your component through event bindings.

If you want your component to notify his parent about something you can use the Output decorator with EventEmitter to create a custom event.

@Component({
selector: 'add-todo',
template: `
<input type="text" placeholder="Add todo.." [formControl]="control">
<button (click)="add.next(control.value)">Add</button>
`,
})
export class AddTodoComponent {
control : FormControl = new FormControl("");
@Output() add = new EventEmitter();
}
<add-todo (add)="addTodo($event)"></add-todo>
What is EventEmitter .. a subject ??
export declare class EventEmitter<T> extends Subject<T> {
__isAsync: boolean;
constructor(isAsync?: boolean);
emit(value?: T): void;
subscribe(generatorOrNext?: any, error?: any, complete?: any): any;
}
💪 You have the power of Rx 💪
@Output() add = new EventEmitter().filter(v => !!v);
@Output() add = new BehaviorSubject("Awesome").filter(v => !!v);
EventEmitters are not DOM events
they can't bubble to top of DOM
Event emitter !== DOM

You can't emit event from todo to todoPage component
Solution is
Keep passing the event up the tree
export class TodoComponent {
@Output() toggle = new EventEmitter<any>();
}
export class TodosComponent {
@Output() toggle = new EventEmitter<any>();
}
export class TodosPageComponent {
toggle($event) {}
}
Too much nesting here
Lets do it in native way !
@Component({
selector: 'app-todo',
template: `
<p (click)="toggleTodo(todo)">
{{todo.title}}
</p>
`
})
export class TodoComponent {
@Input() todo;
constructor(private el: ElementRef) {}
toggleTodo(todo) {
this.el.nativeElement
.dispatchEvent(new CustomEvent('toggle-todo', {
detail: todo,
bubbles: true
}));
}
}
Native DOM not a good choice
Lets do using service
@Injectable()
export class TodosService {
private _toggle = new Subject();
toggle$ = this._toggle.asObservable();
toggle(todo) {
this._toggle.next(todo);
}
}
export class TodoComponent {
constructor(private todosService: TodosService) {}
toggle(todo) {
this.todosService.toggle(todo);
}
}
export class TodosPageComponent {
constructor(private todosService: TodosService) {
todosService.toggle$.subscribe(..);
}
}
View Encapsulation
import {Component, ViewEncapsulation}
from 'angular2/angular2';
@component({
selector: 'app',
template: `<p class="green">`,
style: [`
.green { color: green}
`],
encapsulation: 'ViewEncapsulation.Native'
// .Emulated .None
})
export class App {
constructor() {}
}
-
ViewEncapsulation.Emulated
- angular2 view encapsulation enabled // default
-
ViewEncapsulation.None
- No view encapsulation
-
ViewEncapsulation.Native
- view encapsulation using shadow dom
Directives
import {Directive, ElementRef} from 'angular2/angular2';
@Directive({
selector: '[bold]'
})
export class BoldDirective {
constructor(el: ElementRef) {
el.nativeElement.style.fontWeight = 'bold';
}
}
<div class="myapp">
<p bold> Hello world </p>
</div>
Dependency Injection
class Vehicle {
constructor() {
var engine = new Engine();
engine.build();
}
}
Constructor injection
class Vehicle {
constructor(engine: Engine) {
engine.build();
}
}
class Engine {
constructor(nutsNBolts: NutsNBolts) {
nutsNBolts.fit();
}
}
class NutsNBolts {
constructor() {
.....
}
fit() {
}
}
new Vehicle(new Engine(new NutsNBolts()));
// Parent component
import {Component} from 'angular2/angular2';
import {Bootstrap} from 'angular2/angular2';
import {UserService} from './userservice.js';
@Component({ template: `<div> My App </div>` ... })
export class App {
constructor() {
}
}
Bootstrap(App,[UserService]); //UserService available in entire app.
//Child component
import {Component} from 'angular2/angular2';
import {UserService} from './userservice.js';
...
@Component({ ... })
export class SomeComponent {
constructor(user: UserService) { //Singleton
user.dosomething();
}
}
Global Injection
By default all objects injected are singleton
// parent.ts -- parent component
import {RoutineService} from './componentservice';
import {Child} from './child';
@Component({
......
template: `<div>Parent component <child></child> </div>`,
directives: [Child]
providers: [RoutineService]
// viewProviders: [RoutineService]
})
export class App {
constructor(routineservice: RoutineService) {
routineservice.addRoutine(["eat", "sleep", "code"]);
}
}
//child.ts -- child component
import {RoutineService} from './routineservice.js';
@Component({
selector: 'child',
template `<p> I am child component </p>`
})
export class SomeComponent {
constructor(routineservice: RoutineService) { //Singleton
routineservice.deleteRoutine(["sleep"]);
}
}
Component level injection
PIPES
<!-- Date PIPE --!>
<p>{{date | date:'mediumDate'}}</p>
<!-- Sep 1, 2015 --!>
<p>{{date | date:'yMMMMd'}}</p>
<!-- September 1, 2015 --!>
<p>{{date | date:'shortTime'}}</p>
<!-- 3:50 pm --!>
<!-- CURRENCY PIPE --!>
<p>{{43 | currency: 'USD' : true}}</p>
<!-- $43 --!>
<p>{{43 | currency: 'USD' : true : '2.2'}} </p>
<!--$43.00 --!>
<p>{{43 | currency: 'USD' : true : '3.3'}} </p>
<!--$043.000 --!>
Angular2 inbuilt pipes
- currency
- date
- uppercase
- json
- limitTo
- lowercase
- orderBy
- filter
- async
- decimal
- percent
- number
Async Pipes
@Component({
template:
`
<div>
<h1>My Component </h1>
This component is ... {{lazydata | async}}
</div>
`
});
export class App{
lazyData: Promise<string> = null;
constructor() {
this.lazyData = new Promise<string>((resolve: any, reject: any) => {
setTimeout(()=> resolve("lazy"), 3000);
})
}
}
Async pipe also works with Observables.
Async calls

- Http calls return observables.
- Observable is of a love child of Promise and collection/set
- Observable is alias to RxJs Observable
- Rxjs is reactive programming libraray
import {Http} from 'angular2/angular2';
import {Earthquake} from '../models/earthquake';
class EarthquakeService() {
.
.
.
getEarthquakeData(callback:(data: any[]) => void) {
this.http.get('http://earthquake-report.com/feeds/recent-eq?json')
.map((response: any) => {
return response.json();
})
.map((jsonData: any[]) => {
jsonData.forEach((item) => {
this.earthquakeData.push(new Earthquake(item));
});
return this.earthquakeData;
})
.subscribe(
(data:any) => callback(this.earthquakeData), //OnNext
(err:any) => console.log(err), //OnError
() => console.log("call completed") //OnComplete
);
}
}
}
References
- http://blog.thoughtram.io
- http://angularconnect.com/sessions
- https://angular.io
- https://disqus.com/home/forum/victorsavkinsblog
- https://github.com/abhishek-agashe/angular2-playground
?
Angular 5 Advance webinars 02
By Tarun Sharma
Angular 5 Advance webinars 02
- 532