SlideShare a Scribd company logo
Component Communication
What is a component
@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>
Parent → Child
@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
@Input() Demo
Child → Parent
@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();
}
@Output() Demo
Sibling → Sibling
@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++;
}
}
Sibling Demo
user.service.ts
export class UserService {
users: User[] = [];
}
user.service.ts
export class UserService {
private users$ = new BehaviorSubject([]);
}
user.service.ts
export class UserService {
private users$ = new BehaviorSubject([]);
addUser(user) {
let users = [user, ...this.users$.getValue()];
this.users$.next(users);
}
}
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);
}
}
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();
}
}
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));
}
}
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));
}
}
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));
}
}
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));
}
}
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));
}
}
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();
}
}
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();
}
}
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));
}
);
}
http://rxmarbles.com/#combineLatest
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);
}
}
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);
}
}
List Search
User Service
users$ = BehaviorSubject([
'User1',
'User2',
'User3'
])
List Search
User Service
users$ = BehaviorSubject([
'User1',
'User2',
'User3'
])
[
'User1',
'User2',
'User3'
]
List Search
User1 ✖
User2 ✖
User3 ✖
User Service
users$ = BehaviorSubject([
'User1',
'User2',
'User3'
])
[
'User1',
'User2',
'User3'
]
User1
User2
User3
List Search
User1 ✖
User2 ✖
User3 ✖
User1
User2
User3
User Service
users$ = BehaviorSubject([
'User1',
'User2',
'User3'
])
removeUser('User2')
List Search
User1 ✖
User2 ✖
User3 ✖
User1
User2
User3
User Service
users$ = BehaviorSubject([
'User1',
'User3'
])
removeUser('User2')
List Search
User1 ✖
User2 ✖
User3 ✖
User1
User2
User3
User Service
users$ = BehaviorSubject([
'User1',
'User3'
])
[
'User1',
'User3'
]
removeUser('User2')
List Search
User1 ✖
User3 ✖
User1
User3
User Service
users$ = BehaviorSubject([
'User1',
'User3'
])
[
'User1',
'User3'
]
removeUser('User2')
Angular 2 Component Communication - Talk by Rob McDiarmid
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();
}
};
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();
}
*/
};
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();
}
*/
}
};
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();
*/
}
};
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();
*/
}
};
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();
*/
}
};
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;
}
};
app.module.ts
import {userReducer} from "./reducers/userReducer";
@NgModule({
imports: [StoreModule.provideStore({ users: userReducer })
],
declarations: [/*...*/],
providers: [/*...*/],
bootstrap: [/*...*/]
})
class AppModule { }
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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}});
}
}
Takeaways
- Everything is a component!!!
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()
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
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);
}
Takeaways - ngrx/store (Redux)
- ngrx/store library brings redux like
approach to Angular 2
- Centralized state
- One way data flow
Further Reading
Angular Cookbook
Component Interaction
rxjs/store
github.com/ngrx/store
egghead.io
Building Angular 2
Components
egghead.io
Step-by-Step Async
JavaScript with RxJS
Rob McDiarmid
Slides: tinyurl.com/ng2-components
@robianmcd

More Related Content

PDF
Angular performance slides
PDF
Angular JS2 Training Session #2
PPTX
How to perform debounce in react
PPTX
Angular2 + rxjs
PDF
Workshop 26: React Native - The Native Side
PDF
Angular 2 introduction
PDF
Workshop 19: ReactJS Introduction
PPTX
Academy PRO: React native - navigation
Angular performance slides
Angular JS2 Training Session #2
How to perform debounce in react
Angular2 + rxjs
Workshop 26: React Native - The Native Side
Angular 2 introduction
Workshop 19: ReactJS Introduction
Academy PRO: React native - navigation

What's hot (20)

PDF
What's Coming in Spring 3.0
PDF
Workshop 17: EmberJS parte II
PDF
Simplified Android Development with Simple-Stack
PDF
Practical Protocol-Oriented-Programming
PDF
Workshop 20: ReactJS Part II Flux Pattern & Redux
PDF
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
PDF
Building Web Interface On Rails
PDF
Workshop 23: ReactJS, React & Redux testing
PDF
Workshop 25: React Native - Components
PPTX
ReactJs presentation
PPTX
Developing New Widgets for your Views in Owl
PPT
Jsp/Servlet
PPTX
Architecting Single Activity Applications (With or Without Fragments)
PPTX
Paging Like A Pro
PDF
Rails Best Practices
PDF
React Native: JS MVC Meetup #15
PDF
State management in android applications
PDF
Redux vs Alt
PDF
Workshop 13: AngularJS Parte II
PDF
Workshop 14: AngularJS Parte III
What's Coming in Spring 3.0
Workshop 17: EmberJS parte II
Simplified Android Development with Simple-Stack
Practical Protocol-Oriented-Programming
Workshop 20: ReactJS Part II Flux Pattern & Redux
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
Building Web Interface On Rails
Workshop 23: ReactJS, React & Redux testing
Workshop 25: React Native - Components
ReactJs presentation
Developing New Widgets for your Views in Owl
Jsp/Servlet
Architecting Single Activity Applications (With or Without Fragments)
Paging Like A Pro
Rails Best Practices
React Native: JS MVC Meetup #15
State management in android applications
Redux vs Alt
Workshop 13: AngularJS Parte II
Workshop 14: AngularJS Parte III
Ad

Viewers also liked (17)

PPTX
Social, Mobile & The Future of Retail
PPT
'Did He Really Say That?" effective component communication
PPT
7 Principles of Communications
PPTX
Dryland Systems Gender Component Communication
PPTX
React. Flux. Redux. by Andrey Kolodnitskiy
PPTX
Into the Land of lambda, One Programmer's Journey Into Functional Programming
PDF
Understanding Redux — Ilya Gelman
PDF
Social, Mobile & The Future of Retail
PPTX
Teaching Business Writing and Oral Communication
PDF
Dumb and smart components + redux (1)
PDF
Application architecture doesn't have to suck
PPTX
Event Sourcing your AngularJS applications
PPTX
React. Flux. Redux
PDF
Progressive Web Apps
DOCX
Derechos del niño
PPTX
Comercio electronico
PDF
Ritusmoi_Kaushik_Resume
Social, Mobile & The Future of Retail
'Did He Really Say That?" effective component communication
7 Principles of Communications
Dryland Systems Gender Component Communication
React. Flux. Redux. by Andrey Kolodnitskiy
Into the Land of lambda, One Programmer's Journey Into Functional Programming
Understanding Redux — Ilya Gelman
Social, Mobile & The Future of Retail
Teaching Business Writing and Oral Communication
Dumb and smart components + redux (1)
Application architecture doesn't have to suck
Event Sourcing your AngularJS applications
React. Flux. Redux
Progressive Web Apps
Derechos del niño
Comercio electronico
Ritusmoi_Kaushik_Resume
Ad

Similar to Angular 2 Component Communication - Talk by Rob McDiarmid (20)

PDF
Django Class-based views (Slovenian)
PPTX
Orchestrating things in Angular application
PPTX
How to Bring Common UI Patterns to ADF
PDF
Clean Javascript
PDF
How te bring common UI patterns to ADF
ODP
Codemotion appengine
DOCX
Week 12 code
KEY
Symfony2 Building on Alpha / Beta technology
PPT
Easy rest service using PHP reflection api
PDF
준비하세요 Angular js 2.0
PDF
Doctrine For Beginners
PDF
Intro programacion funcional
PDF
Symfony2 from the Trenches
PDF
Юрий Буянов «Squeryl — ORM с человеческим лицом»
PDF
Be RESTful (Symfony Camp 2008)
ODP
Dependency injection in Scala
PDF
Action View Form Helpers - 2, Season 2
PDF
Structuring React.js Components
PDF
4Developers 2018: Structuring React components (Bartłomiej Witczak)
PDF
Building Large jQuery Applications
Django Class-based views (Slovenian)
Orchestrating things in Angular application
How to Bring Common UI Patterns to ADF
Clean Javascript
How te bring common UI patterns to ADF
Codemotion appengine
Week 12 code
Symfony2 Building on Alpha / Beta technology
Easy rest service using PHP reflection api
준비하세요 Angular js 2.0
Doctrine For Beginners
Intro programacion funcional
Symfony2 from the Trenches
Юрий Буянов «Squeryl — ORM с человеческим лицом»
Be RESTful (Symfony Camp 2008)
Dependency injection in Scala
Action View Form Helpers - 2, Season 2
Structuring React.js Components
4Developers 2018: Structuring React components (Bartłomiej Witczak)
Building Large jQuery Applications

Recently uploaded (20)

PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PPTX
Cloud computing and distributed systems.
PDF
KodekX | Application Modernization Development
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Omni-Path Integration Expertise Offered by Nor-Tech
PDF
NewMind AI Monthly Chronicles - July 2025
PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
PPTX
Telecom Fraud Prevention Guide | Hyperlink InfoSystem
PDF
Newfamily of error-correcting codes based on genetic algorithms
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
AI And Its Effect On The Evolving IT Sector In Australia - Elevate
PDF
Reimagining Insurance: Connected Data for Confident Decisions.pdf
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Smarter Business Operations Powered by IoT Remote Monitoring
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
CroxyProxy Instagram Access id login.pptx
PDF
cuic standard and advanced reporting.pdf
PDF
REPORT: Heating appliances market in Poland 2024
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
20250228 LYD VKU AI Blended-Learning.pptx
Dropbox Q2 2025 Financial Results & Investor Presentation
Cloud computing and distributed systems.
KodekX | Application Modernization Development
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Omni-Path Integration Expertise Offered by Nor-Tech
NewMind AI Monthly Chronicles - July 2025
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
Telecom Fraud Prevention Guide | Hyperlink InfoSystem
Newfamily of error-correcting codes based on genetic algorithms
Understanding_Digital_Forensics_Presentation.pptx
AI And Its Effect On The Evolving IT Sector In Australia - Elevate
Reimagining Insurance: Connected Data for Confident Decisions.pdf
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Smarter Business Operations Powered by IoT Remote Monitoring
Review of recent advances in non-invasive hemoglobin estimation
CroxyProxy Instagram Access id login.pptx
cuic standard and advanced reporting.pdf
REPORT: Heating appliances market in Poland 2024
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication

Angular 2 Component Communication - Talk by Rob McDiarmid

  • 2. What is a component
  • 3. @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>
  • 5. @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++; } }
  • 13. user.service.ts export class UserService { users: User[] = []; }
  • 14. user.service.ts export class UserService { private users$ = new BehaviorSubject([]); }
  • 15. user.service.ts export class UserService { private users$ = new BehaviorSubject([]); addUser(user) { let users = [user, ...this.users$.getValue()]; this.users$.next(users); } }
  • 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); } }
  • 29. List Search User Service users$ = BehaviorSubject([ 'User1', 'User2', 'User3' ])
  • 30. List Search User Service users$ = BehaviorSubject([ 'User1', 'User2', 'User3' ]) [ 'User1', 'User2', 'User3' ]
  • 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}}); } }
  • 53. Takeaways - Everything is a component!!!
  • 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
  • 58. Further Reading Angular Cookbook Component Interaction rxjs/store github.com/ngrx/store egghead.io Building Angular 2 Components egghead.io Step-by-Step Async JavaScript with RxJS