Outline
Communicating with components can be essential given the right reason. In AngularJS, we could achieve this with the use of $broadcast
or $emit
. However, in Angular, we can use a new style of communicating using EventEmitters like Output. Another option is to communicate between child and parent components using a Service. Complex applications may even choose to implement a communication and state management strategy using Akita or NgRX.
Unlike $broadcast
and $emit
, data flows differently in Angular. A single Output metadata factory is only able to bridge the layer of communication between a parent and child component. Beyond that, we would need to leverage more advanced techniques like creating RxJS Subscription events. We will look into this later on in this tutorial.
For now, all you need to know is that there are two basic ways of interacting between components:
Inputs allow you to pass data down to a child component
Outputs allow you to emit data upwards to a parent component
Let us take a look at a simple example. Using our example from before, we will be improving our app so the name in the header can be changed by either the HeaderComponent
or the AppComponent
. We'll do this by having AppComponent
pass the current name down to an Input on HeaderComponent
, and HeaderComponent
can use an Output to emit a new name up to the AppComponent
.
The code will look something like the following:
app/shared/layout/header.component.ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'layout-header',
templateUrl: 'src/app/shared/layout/header.component.html'
})
export class HeaderComponent {
constructor() {}
// name: string = 'Angular';
@Input() name: string;
@Output() onNameChanged = new EventEmitter<string>();
changeName(newName: string) {
this.onNameChanged.emit(newName);
}
}
And the template will now have a button to call the changeName
method:
app/shared/layout/header.component.html
<div>
<button (click)="changeName('Cookie Monster')">
Change name
</button>
<h2>Hello {{name}}</h2>
</div>
Over in the AppComponent
, lets create a method that allows the template to change the name.
app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: 'src/app/app.component.html'
})
export class AppComponent {
constructor() {}
name: string = 'Angular';
setName(newName: string) {
this.name = newName;
}
}
Its template will now pass down the name and hook into the HeaderComponent
's onNameChanged
output:
<layout-header [name]="name" (onNameChanged)="setName($event)"> </layout-header>
Nested components rule!
Now this is a new territory for Angular. The onNameChanged attribute is wrapped in parentheses. In Angular, this means that this an Output
attribute for our child component. It also uniquely defines a channel by which our components can communicate through. Other Angular directives like NgModel
do this when creating bindings between an element and its relative component.
You can view the working code here:
And that is it! We can now communicate to and from our child component via the parent. No need for $rootScope
or $broadcast
or even $emit
! For more information on communication between components, I suggest taking a deep look at the Official Tutorial on Component Communication by our friends at the Angular Team from Google.