More Related Content Similar to Angular 2 Component Communication - Talk by Rob McDiarmid (20) Angular 2 Component Communication - Talk by Rob McDiarmid5. @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
8. @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();
}
11. @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++;
}
}
16. user.service.ts
export 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);
}
}
17. user.service.ts
export 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();
}
}
18. 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));
}
}
19. 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));
}
}
20. 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));
}
}
21. 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));
}
}
22. 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));
}
}
23. 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();
}
}
24. 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();
}
}
25. 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));
}
);
}
27. 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);
}
}
28. 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);
}
}
31. List Search
User1 ✖
User2 ✖
User3 ✖
User Service
users$ = BehaviorSubject([
'User1',
'User2',
'User3'
])
[
'User1',
'User2',
'User3'
]
User1
User2
User3
32. List Search
User1 ✖
User2 ✖
User3 ✖
User1
User2
User3
User Service
users$ = BehaviorSubject([
'User1',
'User2',
'User3'
])
removeUser('User2')
33. List Search
User1 ✖
User2 ✖
User3 ✖
User1
User2
User3
User Service
users$ = BehaviorSubject([
'User1',
'User3'
])
removeUser('User2')
34. List Search
User1 ✖
User2 ✖
User3 ✖
User1
User2
User3
User Service
users$ = BehaviorSubject([
'User1',
'User3'
])
[
'User1',
'User3'
]
removeUser('User2')
35. List Search
User1 ✖
User3 ✖
User1
User3
User Service
users$ = BehaviorSubject([
'User1',
'User3'
])
[
'User1',
'User3'
]
removeUser('User2')
37. user.service.ts
export 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();
}
};
38. user.service.ts
export 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();
}
*/
};
39. user.service.ts
export 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();
}
*/
}
};
40. user.service.ts
export 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();
*/
}
};
41. user.service.ts
export 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();
*/
}
};
42. user.service.ts
export 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();
*/
}
};
43. user.service.ts
export 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;
}
};
44. app.module.ts
import {userReducer} from "./reducers/userReducer";
@NgModule({
imports: [StoreModule.provideStore({ users: userReducer })
],
declarations: [/*...*/],
providers: [/*...*/],
bootstrap: [/*...*/]
})
class AppModule { }
45. 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);
}
}
46. 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);
}
}
47. 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);
}
}
48. 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);
}
}
49. 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);
}
}
50. 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);
}
}
51. 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);
}
}
52. 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}});
}
}
54. 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()
55. 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
56. 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 components
private state$ = new BehaviorSubject<>({});
doSomething(thing) {
this.state$.next(thing);
}
57. Takeaways - ngrx/store (Redux)
- ngrx/store library brings redux like
approach to Angular 2
- Centralized state
- One way data flow