SlideShare a Scribd company logo
1 of 59
Download to read offline
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')
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

What's hot

Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On Rails
Wen-Tien Chang
 

What's hot (20)

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

Viewers also liked

7 Principles of Communications
7 Principles of Communications7 Principles of Communications
7 Principles of Communications
dexpan
 
Derechos del niño
Derechos del niñoDerechos del niño
Derechos del niño
Tony Hotter
 
Comercio electronico
Comercio electronicoComercio electronico
Comercio electronico
mariangelarod
 

Viewers also liked (17)

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

Similar to Angular 2 Component Communication - Talk by Rob McDiarmid

Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
Luka Zakrajšek
 
Юрий Буянов «Squeryl — ORM с человеческим лицом»
Юрий Буянов «Squeryl — ORM с человеческим лицом»Юрий Буянов «Squeryl — ORM с человеческим лицом»
Юрий Буянов «Squeryl — ORM с человеческим лицом»
e-Legion
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
Fabien Potencier
 
Action View Form Helpers - 2, Season 2
Action View Form Helpers - 2, Season 2Action View Form Helpers - 2, Season 2
Action View Form Helpers - 2, Season 2
RORLAB
 

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

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

Recently uploaded

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Recently uploaded (20)

A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 

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')
  • 36.
  • 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