Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62
Subscribe to my email list now at http://jauyeung.net/subscribe/
Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.
In this article, we’ll look at some complex examples of Angular component interaction.
Parent Interacts with Child Via Local Variable
We can create template reference variable for the child element and then reference that variable within the template to access a child component’s variable in the parent.
For example, we can write the following code:
app.module.ts
:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { PersonComponent } from './person/person.component';
@NgModule({
declarations: [
AppComponent,
PersonComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
person = {};
}
app.component.html
:
<app-person #appPerson></app-person>
<button (click)='appPerson.setPerson()'>Set Person</button>
<p>{{appPerson.person.name}}</p>
person.component.ts
:
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-person',
templateUrl: './person.component.html',
styleUrls: ['./person.component.css']
})
export class PersonComponent {
person = {};
setPerson() {
this.person = { name: 'Jane' };
}
}
We left person.component.html
blank.
In the code above, we have the PersonComponent
, which is the child of AppComponent
.
In PeronComponent
, we have the person
variable and the setPerson
method.
Then in app.component.html
, we added a #appPerson
template variable so that we can access its variable.
Then we used it to call PersonComponent
‘s setPerson
method on the Set Person button.
We also displayed appPerson.person.name
from PersonComponent
in the p element.
When we click the Set Person button, the p tag automatically updates to show the value of appPerson.person.name
set by setPerson
.
Parent calls an @ViewChild()
In the previous example, we access a child component’s local variables. It’s simple and easy, but it’s limited because the parent-child wiring is all done in the parent.
The parent component has no access to the child.
To access the child component in the parent component’s code, we can use a ViewChild
.
To do use ViewChild
, we can write the following code:
app.module.ts
:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { PersonComponent } from './person/person.component';
@NgModule({
declarations: [
AppComponent,
PersonComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
:
import { Component, ViewChild } from '@angular/core';
import { PersonComponent } from './person/person.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
@ViewChild(PersonComponent, {static: false})
private personComponent: PersonComponent;
setPerson(){
this.personComponent.setPerson();
}
}
app.component.html
:
<button (click)='setPerson()'>Set Person</button>
<p>{{personComponent && personComponent.person.name}}</p>
<app-person></app-person>
person.component.ts
:
import { Component } from '@angular/core';
@Component({
selector: 'app-person',
templateUrl: './person.component.html',
styleUrls: ['./person.component.css']
})
export class PersonComponent {
person = {};
setPerson() {
this.person = { name: 'Jane' };
}
}
We left person.component.html
blank again.
In the code above, we have the same person
and setPerson
members in PersonComponent
.
Then in in AppComponent
, we added the ViewChild
as follows:
@ViewChild(PersonComponent, {static: false})
private personComponent: PersonComponent;
to access the PersonComponent
directly from within AppComponent
. We need the app-person
component in our PersonComponent
template even though we don’t show anything in it so that AppComponent
can access PersonComponent
.
Then we just call the methods directly in AppComponent
's setPerson
method.
Also, we accessed the app-person
component within the template with:
<p>{{personComponent && personComponent.person.name}}</p>
to show the person.name
property from PersonComponent
.
Parent and Children Communicate via a Service
Parent and child components can also communicate via a shared service.
We can create a service and then send the data to an Observable in the service from the child component which the parent component listens to so that it can get the latest data.
To do this, we can write the following:
app.module.ts
:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { PersonComponent } from './person/person.component';
import { PersonService } from './person.service';
@NgModule({
declarations: [
AppComponent,
PersonComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [PersonService],
bootstrap: [AppComponent]
})
export class AppModule { }
person.service.ts
:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class PersonService {
private personSource = new Subject();
personSource$ = this.personSource.asObservable();
announcePerson(person) {
this.personSource.next(person);
}}
app.component.ts
:
import { Component } from '@angular/core';
import { PersonService } from './person.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
person = {}; constructor(private personService: PersonService) {
personService.personSource$.subscribe(
person => {
this.person = person;
});
}
}
app.component.html
:
<app-person></app-person>
<p>{{person.name}}</p>
person.component.ts
:
import { Component } from '@angular/core';
import { PersonService } from '../person.service';
@Component({
selector: 'app-person',
templateUrl: './person.component.html',
styleUrls: ['./person.component.css']
})
export class PersonComponent {
constructor(private personService: PersonService) { }
setPerson() {
this.personService.announcePerson({ name: 'Jane' });
}
}
person.component.html
:
<button (click)='setPerson()'>Set Person</button>
In the code above, we have the PersonService
, whre we created a new Subject
and converted it to an Observable.
In the annoucePerson
method, we take in a person
object and call next
on personSource
to broadcast the person
object via the personSource$
Observable.
Then in AppComponent
, we subscribe to the personSource$
Observable by writing:
personService.personSource$.subscribe(
person => {
this.person = person;
});
to get the latest value of person
from the Observable.
In person.component.html
, we added a button as follows:
<button (click)='setPerson()'>Set Person</button>
When we click it, we call the setPerson
method, which calls the annoucePerson
method from the PersonService
we have above with the object that we wanted to pass in.
Since AppComponent
subscribed to the personSource$
Observable, we should get the latest value of person.name
.
Therefore, when we click Set Person, we should get ‘Jane’ displayed on the screen.
Conclusion
We can communicate between parent and child components in many ways.
We can add a template variable on the child component in the parent template and then access its public members on the parent template.
To access a child component’s members in the parent component, we can do it via the ViewChild
which references the child component in the parent component.
Lastly, we can create a service that’s shared between the parent and child component, and then called the Subject
‘s next
method to broadcast the message via the Observable.
Then the parent subscribes to the Observable and gets the latest value broadcasted from there.