angular 2 component communication - talk by rob mcdiarmid

59
Component Communication

Upload: amrita-chopra

Post on 22-Mar-2017

318 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Angular 2 Component Communication - Talk by Rob McDiarmid

Component Communication

Page 2: Angular 2 Component Communication - Talk by Rob McDiarmid

What is a component

Page 3: Angular 2 Component Communication - Talk by Rob McDiarmid

@Component({ selector: 'myComp', template: `<div> Content: {{myVar}} </div>`})class MyComponent { myVar: string;

constructor() { this.myVar = 'hello'; }}

Output

Input<html> <myComp></myComp></html>

<html> <myComp> <div> Content: hello </div> </myComp></html>

Page 4: Angular 2 Component Communication - Talk by Rob McDiarmid

Parent → Child

Page 5: Angular 2 Component Communication - Talk by Rob McDiarmid

@Component({ selector: 'parent', template: `<div> Parent content <child [param]="myVar"></child> Parent content</div>`})class ParentComponent { myVar = 'hello';}

@Component({ selector: 'child', template: '<div>Child: {{param}}</div>'})class ChildComponent { @Input() param: string;}

<html> <parent> <div> Parent content <child> Child hello </child> Parent content </div> </parent></html>

Output

Input<html> <parent></parent></html>

wizardComp

Page 6: Angular 2 Component Communication - Talk by Rob McDiarmid

@Input() Demo

Page 7: Angular 2 Component Communication - Talk by Rob McDiarmid

Child → Parent

Page 8: Angular 2 Component Communication - Talk by Rob McDiarmid

@Component({ selector: 'parent', template: `<div> <child (childEvent)="handelChildEvent($event)"></child></div>`})class ParentComponent { handelChildEvent(message) { console.log(message); }}

@Component({ selector: 'child', template: ` <button (click)="childEvent.emit('clicked')">Click me</button>`})class ChildComponent { @Output() childEvent = new EventEmitter();}

Page 9: Angular 2 Component Communication - Talk by Rob McDiarmid

@Output() Demo

Page 10: Angular 2 Component Communication - Talk by Rob McDiarmid

Sibling → Sibling

Page 11: Angular 2 Component Communication - Talk by Rob McDiarmid

@Component({ selector: 'sibling2', template: `<button (click)="myService.increment()"> Increment</button>`})class Sibling2Component { constructor(public myService: MyService) {

}}

@Component({ selector: 'sibling1', template: `{{myService.counter}}`})class Sibling1Component { constructor(public myService: MyService) {

}}

class MyService { counter: number = 0;

increment() { this.counter++; }}

Page 12: Angular 2 Component Communication - Talk by Rob McDiarmid

Sibling Demo

Page 13: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport class UserService { users: User[] = [];}

Page 14: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport class UserService { private users$ = new BehaviorSubject([]);}

Page 15: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport class UserService { private users$ = new BehaviorSubject([]);

addUser(user) { let users = [user, ...this.users$.getValue()]; this.users$.next(users); }}

Page 16: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport class UserService { private users$ = new BehaviorSubject([]);

addUser(user) { let users = [user, ...this.users$.getValue()]; this.users$.next(users); }

removeUser(user) { let users = this.users$.getValue().filter(u => u !== user); this.users$.next(users); }}

Page 17: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport class UserService { private users$ = new BehaviorSubject([]);

addUser(user) { let users = [user, ...this.users$.getValue()]; this.users$.next(users); }

removeUser(user) { let users = this.users$.getValue().filter(u => u !== user); this.users$.next(users); }

getUsers() { return this.users$.asObservable(); }}

Page 18: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of filteredUsers"> <input #firstName (keyup)="filterUsers(firstName.value)"></div>`})export class UserSearchComponent { filteredUsers: User[];

constructor(public userService: UserService) { }

filterUsers(search) { this.filteredUsers = this.userService.users.filter(user => user.firstName.includes(search)); }}

Page 19: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of filteredUsers"> <input #firstName (keyup)="filterUsers(firstName.value)"></div>`})export class UserSearchComponent { users: Observable<User[]>;

constructor(public userService: UserService) { this.users = userService.getUsers(); }

filterUsers(search) { this.filteredUsers = this.userService.users.filter(user => user.firstName.includes(search)); }}

Page 20: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of filteredUsers"> <input #firstName (keyup)="filterUsers(firstName.value)"></div>`})export class UserSearchComponent { users: Observable<User[]>;

constructor(public userService: UserService) { this.users = userService.getUsers(); }

filterUsers(search) { this.filteredUsers = this.userService.users.filter(user => user.firstName.includes(search)); }}

Page 21: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> <input #firstName (keyup)="filterUsers(firstName.value)"></div>`})export class UserSearchComponent { users: Observable<User[]>;

constructor(public userService: UserService) { this.users = userService.getUsers(); }

filterUsers(search) { this.filteredUsers = this.userService.users.filter(user => user.firstName.includes(search)); }}

Page 22: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> <input #firstName (keyup)="filterUsers(firstName.value)"></div>`})export class UserSearchComponent { users: Observable<User[]>;

constructor(public userService: UserService) { this.users = userService.getUsers(); }

filterUsers(search) { this.filteredUsers = this.userService.users.filter(user => user.firstName.includes(search)); }}

Page 23: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> <input #firstName (keyup)="firstNameSearch.next(firstName.value)"></div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public userService: UserService) { this.users = userService.getUsers(); }}

Page 24: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> <input #firstName (keyup)="firstNameSearch.next(firstName.value)"></div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public userService: UserService) { this.users = userService.getUsers(); }}

Page 25: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> <input #firstName (keyup)="firstNameSearch.next(firstName.value)"></div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public userService: UserService) { this.users = Observable.combineLatest( userService.getUsers(), this.firstNameSearch, (users, search) => { return users.filter(user => user.firstName.includes(search)); } ); }}

Page 27: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> ... </div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public userService: UserService) { this.users = Observable.combineLatest( userService.getUsers(), this.firstNameSearch, (users, search) => { ... } ); }

removeUser(user: User) { this.userService.users = this.userService.users.filter(u => u !== user); this.filterUsers(this.firstName.nativeElement.value); }}

Page 28: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> ... </div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public userService: UserService) { this.users = Observable.combineLatest( userService.getUsers(), this.firstNameSearch, (users, search) => { ... } ); }

removeUser(user: User) { this.userService.removeUser(user); }}

Page 29: Angular 2 Component Communication - Talk by Rob McDiarmid

List Search

User Service

users$ = BehaviorSubject([ 'User1', 'User2', 'User3'])

Page 30: Angular 2 Component Communication - Talk by Rob McDiarmid

List Search

User Service

users$ = BehaviorSubject([ 'User1', 'User2', 'User3'])

[ 'User1', 'User2', 'User3']

Page 31: Angular 2 Component Communication - Talk by Rob McDiarmid

List Search

User1 ✖User2 ✖User3 ✖

User Service

users$ = BehaviorSubject([ 'User1', 'User2', 'User3'])

[ 'User1', 'User2', 'User3']

User1User2User3

Page 32: Angular 2 Component Communication - Talk by Rob McDiarmid

List Search

User1 ✖User2 ✖User3 ✖

User1User2User3

User Service

users$ = BehaviorSubject([ 'User1', 'User2', 'User3'])

removeUser('User2')

Page 33: Angular 2 Component Communication - Talk by Rob McDiarmid

List Search

User1 ✖User2 ✖User3 ✖

User1User2User3

User Service

users$ = BehaviorSubject([ 'User1', 'User3'])

removeUser('User2')

Page 34: Angular 2 Component Communication - Talk by Rob McDiarmid

List Search

User1 ✖User2 ✖User3 ✖

User1User2User3

User Service

users$ = BehaviorSubject([ 'User1', 'User3'])

[ 'User1', 'User3']

removeUser('User2')

Page 35: Angular 2 Component Communication - Talk by Rob McDiarmid

List Search

User1 ✖User3 ✖

User1User3

User Service

users$ = BehaviorSubject([ 'User1', 'User3'])

[ 'User1', 'User3']

removeUser('User2')

Page 36: Angular 2 Component Communication - Talk by Rob McDiarmid
Page 37: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport class UserService { private users$ = new BehaviorSubject([]);

addUser(user) { let users = [user, ...this.users$.getValue()]; this.users$.next(users); }

removeUser(user) { let users = this.users$.getValue().filter(u => u !== user); this.users$.next(users); }

getUsers() { return this.users$.asObservable(); }};

Page 38: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport const userReducer = (users = [], action) => { /* addUser(user) { let users = [user, ...this.users$.getValue()]; this.users$.next(users); }

removeUser(user) { let users = this.users$.getValue().filter(u => u !== user); this.users$.next(users); }

getUsers() { return this.users$.asObservable(); } */};

Page 39: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport const userReducer = (users = [], action) => { switch (action.type) { /* addUser(user) { let users = [user, ...this.users$.getValue()]; this.users$.next(users); }

removeUser(user) { let users = this.users$.getValue().filter(u => u !== user); this.users$.next(users); }

getUsers() { return this.users$.asObservable(); } */ }};

Page 40: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport const userReducer = (users = [], action) => { switch (action.type) { case 'CREATE_USER': /* let users = [user, ...this.users$.getValue()]; this.users$.next(users); */ case 'DELETE_USER': /* let users = this.users$.getValue().filter(u => u !== user); this.users$.next(users); */ default: /* return this.users$.asObservable(); */ }};

Page 41: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport const userReducer = (users = [], action) => { switch (action.type) { case 'CREATE_USER': return [...users, User.fromMockData()];

case 'DELETE_USER': /* let users = this.users$.getValue().filter(u => u !== user); this.users$.next(users); */ default: /* return this.users$.asObservable(); */ }};

Page 42: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport const userReducer = (users = [], action) => { switch (action.type) { case 'CREATE_USER': return [...users, User.fromMockData()];

case 'DELETE_USER': return users.filter(user => user.id !== action.payload.id);

default: /* return this.users$.asObservable(); */ }};

Page 43: Angular 2 Component Communication - Talk by Rob McDiarmid

user.service.tsexport const userReducer = (users = [], action) => { switch (action.type) { case 'CREATE_USER': return [...users, User.fromMockData()];

case 'DELETE_USER': return users.filter(user => user.id !== action.payload.id);

default: return users; }};

Page 44: Angular 2 Component Communication - Talk by Rob McDiarmid

app.module.tsimport {userReducer} from "./reducers/userReducer";

@NgModule({ imports: [StoreModule.provideStore({ users: userReducer }) ], declarations: [/*...*/], providers: [/*...*/], bootstrap: [/*...*/]})class AppModule { }

Page 45: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> ... </div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public userService: UserService) { this.users = Observable.combineLatest( userService.getUsers(), this.firstNameSearch, (users, search) => { ... } ); }

removeUser(user: User) { this.userService.removeUser(user); }}

Page 46: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> ... </div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public userService: UserService) { this.users = Observable.combineLatest( userService.getUsers(), this.firstNameSearch, (users, search) => { ... } ); }

removeUser(user: User) { this.userService.removeUser(user); }}

Page 47: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> ... </div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public userService: UserService) { this.users = Observable.combineLatest( userService.getUsers(), this.firstNameSearch, (users, search) => { ... } ); }

removeUser(user: User) { this.userService.removeUser(user); }}

Page 48: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> ... </div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public store: Store<AppState>) { this.users = Observable.combineLatest( userService.getUsers(), this.firstNameSearch, (users, search) => { ... } ); }

removeUser(user: User) { this.userService.removeUser(user); }}

Page 49: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> ... </div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public store: Store<AppState>) { this.users = Observable.combineLatest( userService.getUsers(), this.firstNameSearch, (users, search) => { ... } ); }

removeUser(user: User) { this.userService.removeUser(user); }}

Page 50: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> ... </div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public store: Store<AppState>) { this.users = Observable.combineLatest( store.select(s => s.users), this.firstNameSearch, (users, search) => { ... } ); }

removeUser(user: User) { this.userService.removeUser(user); }}

Page 51: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> ... </div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public store: Store<AppState>) { this.users = Observable.combineLatest( store.select(s => s.users), this.firstNameSearch, (users, search) => { ... } ); }

removeUser(user: User) { this.userService.removeUser(user); }}

Page 52: Angular 2 Component Communication - Talk by Rob McDiarmid

userSearch.component.ts@Component({ selector: 'user-search', template: `<div *ngFor="let user of users | async"> ... </div>`})export class UserSearchComponent { users: Observable<User[]>; firstNameSearch = new BehaviorSubject('');

constructor(public store: Store<AppState>) { this.users = Observable.combineLatest( store.select(s => s.users), this.firstNameSearch, (users, search) => { ... } ); }

removeUser(user: User) { this.store.dispatch({type: 'DELETE_USER', payload: {id: user.id}}); }}

Page 53: Angular 2 Component Communication - Talk by Rob McDiarmid

Takeaways

- Everything is a component!!!

Page 54: Angular 2 Component Communication - Talk by Rob McDiarmid

Takeaways - Parent → Child

- Use an @Input() binding on child component

- Use es6 setters or ngOnChanges() to handle changes

- When @Input() doesn’t work, inject a @ViewChild()

Page 55: Angular 2 Component Communication - Talk by Rob McDiarmid

Takeaways - Child → Parent

- Use an @Output() binding on child component

- Pass events to parent through an EventEmitter()@Output() doThing = new EventEmitter();doThing.emit('some event');

- In the parent, get the payload of the event with $event<child (doThing)="handelThing($event)"></child>

- If you can’t use an @Output() binding you can inject the parent component directly into the child

Page 56: Angular 2 Component Communication - Talk by Rob McDiarmid

Takeaways - Sibling → Sibling

- Use a service to communicate between siblings

- Try to avoid sharing mutable state- Use observables to push events out

from a service to componentsprivate state$ = new BehaviorSubject<>({});doSomething(thing) { this.state$.next(thing);}

Page 57: Angular 2 Component Communication - Talk by Rob McDiarmid

Takeaways - ngrx/store (Redux)

- ngrx/store library brings redux like approach to Angular 2

- Centralized state- One way data flow

Page 59: Angular 2 Component Communication - Talk by Rob McDiarmid

Rob McDiarmidSlides: tinyurl.com/ng2-components

@robianmcd