@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() {}
}
  1. ViewEncapsulation.Emulated
    • ​angular2 view encapsulation enabled // default
  2. ViewEncapsulation.None
    • No view encapsulation​
  3. 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

 

?

Made with Slides.com