Complex Angular Component Interaction Examples
Tags: angular, webdev, programming, javascript
Published: 2021-01-23 00:17:49

**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.