Passing Data Between Components - Day Two

We have seen that we can pass the data between the components using the @Input and @Output directives and using event emitters. Let’s see the other two methods - @View child and the services which can be used to pass the data between components.

So, let’s break up the article into two sections; the first one will be ViewChild and another one is the data services.

Passing data using ViewChild

ViewChild is the way that allows the component to be injected into another component and give parent component access to the child component available.

In short, to use the properties of the child component, we can use the ViewChild. To get this working, let's add 2 components in the application we have, namely MasterwithViewChildComponent.ts and ChildwithViewChildComponent.ts.

Next, let us see the ChildwithViewChildComponent.ts and check the following snippet.

  1. import {  
  2.     Component,  
  3.     OnInit  
  4. } from '@angular/core';  
  5. @Component({  
  6.     selector: 'app-childwith-view-child',  
  7.     templateUrl: './childwith-view-child.component.html',  
  8.     styleUrls: ['./childwith-view-child.component.css']  
  9. })  
  10. export class ChildwithViewChildComponent implements OnInit {  
  11.     counter: number = 0;  
  12.     IncreaseNumber(): void {  
  13.         this.counter++;  
  14.     }  
  15.     constructor() {}  
  16.     ngOnInit() {}  
  17. }  

When we see the code snippet, we can see that the class has a normal counter property and a method named IncreaseNumber() which increases the counter by one every time this function is called.

Next, let's look at the code snippet that we have for the Master component one.

  1. import {  
  2.     Component,  
  3.     OnInit,  
  4.     ViewChild  
  5. } from '@angular/core';  
  6. import {  
  7.     ChildwithViewChildComponent  
  8. } from '../childwith-view-child/childwith-view-child.component'  
  9. @Component({  
  10.     selector: 'app-masterwith-view-child',  
  11.     templateUrl: './masterwith-view-child.component.html',  
  12.     styleUrls: ['./masterwith-view-child.component.css']  
  13. })  
  14. export class MasterwithViewChildComponent implements OnInit {  
  15.     @ViewChild(ChildwithViewChildComponent)  
  16.     private childcomponent: ChildwithViewChildComponent;  
  17.     Increase(): void {  
  18.         this.childcomponent.IncreaseNumber();  
  19.     }  
  20.     Dicrease(): void {  
  21.         this.childcomponent.counter--;  
  22.     }  
  23.     constructor() {}  
  24.     ngOnInit() {}  
  25. }  

Let’s look at the things step by step.

  1. Import the ViewChild from the @angular/core
    The @ViewChild decorator is present in the Angular core so we need to import the package

  2. Next, the below code is the most important snippet to check.
    @ViewChild(ChildwithViewChildComponent)
    private childcomponent: ChildwithViewChildComponent;

These lines of the code are used to query the child component and inject the same property inside the local object of the child component which is created in the second line.

It also has two functions IncreaseNumber() and Dicrease(), in which Increase () calls the Function which is present in the child component and Dicrease () reduces the counter property of the child component by 1.

Here, we are. Let's modify the master template with following code.

  1. <p>  
  2.    <b>@ViewChild with Components..</b>  
  3. <br>  
  4. <br>  
  5. <input type="button" value="Increase" (click)=Increase()>  
  6. <input type="button" value="Dicrease" (click)=Dicrease()>  
  7.    <app-childwith-view-child></app-childwith-view-child>  
  8. </p> 

We have instantiated the child component and the two Buttons which will call the Increase and Decrease functions respectively in the component and get the output accordingly.

Passing data using data service

So far, we have seen data sharing between the related components. Now, let’s see how data is shared across the components which are not related. For the components like this, the idea behind having the shared data is for using the shared service which will sync all the data across the components to which it is referred.

To achieve this, let's add the Data Service first which will be holding the data that we need for the components. Let's see the Data.service.ts

  1. import {  
  2.     Injectable  
  3. } from '@angular/core';  
  4. import {  
  5.     BehaviorSubject  
  6. } from 'rxjs'  
  7. @Injectable()  
  8. export class DataService {  
  9.     private messageSource = new BehaviorSubject < string > ("Start");  
  10.     currentmessage = this.messageSource.asObservable();  
  11.     constructor() {}  
  12.     changemessage(message: string): void {  
  13.         this.messageSource.next(message);  
  14.     }  

Above is the code for the DataService class but before going into the details of this class, let us try to understand some snippet available In the code,

  1. Import{Injectable} from ‘@angulr/core’
    This Line which is the first line in the code brings the @Injectable decorator In the code This is used to allow the functionality of the class to be injected and used in the other components or Modules.

  2. Import{BehaviorSubject} from ‘@angular/core’
    It is a subject type which can be used to return a special type of the observable which can be used to subscribe to the various types of the messages.

It also gives us the observables from the subject using the Method as observable() on the behavior subject.

In the above code, we have added the changemessage method which gets the next from the observable subject an return the message.

To consume the service in the components, let's add this service as a provider to the Root Module which is app.module.ts. Let us add the following snippet to the app module.

providers: [DataService],

We have added the Providers to the app module. Now, let's check the components which want to communicate with each other.

Let's see first component.

  1. import {  
  2.     Component,  
  3.     OnInit  
  4. } from '@angular/core';  
  5. import {  
  6.     DataService  
  7. } from '../data.service'  
  8. @Component({  
  9.     selector: 'app-first-component',  
  10.     templateUrl: './first-component.component.html',  
  11.     styleUrls: ['./first-component.component.css']  
  12. })  
  13. export class FirstComponentComponent implements OnInit {  
  14.     message: string = "";  
  15.     constructor(private data: DataService) {}  
  16.     ngOnInit() {  
  17.         this.data.currentmessage.subscribe(message => this.message = message);  
  18.     }  

In this, we are importing the dataservice in the component and we can see that the constructor of the component is following.

  1. constructor(private data:DataService)  
  2. {  
  3. }  

 In this, we are adding the object of the DataService which is singleton object which is created only once.  Next, we are subscribing to any change in the currentmessage property of the dataService which will be assigned to the message property of the class. next is the second component which has code like below.

  1. import {  
  2.     Component,  
  3.     OnInit  
  4. } from '@angular/core';  
  5. import {  
  6.     DataService  
  7. } from '../data.service';  
  8. @Component({  
  9.     selector: 'app-secondcomponent',  
  10.     templateUrl: './secondcomponent.component.html',  
  11.     styleUrls: ['./secondcomponent.component.css']  
  12. })  
  13. export class SecondcomponentComponent implements OnInit {  
  14.     childmessage: string = ""  
  15.     counter: number = 0;  
  16.     constructor(private data: DataService) {}  
  17.     ngOnInit() {  
  18.         this.data.currentmessage.subscribe(Message => this.childmessage = Message);  
  19.     }  
  20.     newmessage(): void {  
  21.         this.data.changemessage("changing counter from sibling " + this.counter++);  
  22.     }  
  23. }  

It also follows the same method when we are subscribing and assigning the value of the currentmessage from the data service to the childmessage property of the class. Also, we have a new method, newmessage, which calls the data.changeMessage() which subsequently changes the property of the messageSource. To run the application, just change the app.component.html somewhat to look like below.

  1. <div><strong>Data passing Using Service</strong><br>  
  2. First component:: <app-first-component></app-first-component>  
  3. <br>  
  4. Second Component:: <app-secondcomponent></app-secondcomponent>  

To sum up, using the DataService to share the data between components, we should adopt the following steps.

  1. Add DataService class decorated with the @Injectable
  2. Use the behavior Subject from the RxJS BehaviorSubject Subject
  3. Subscribe to the changing property an assign to some property In the component

Hope you understood the various ways to handle the data flow between the components with these two articles.

References

  • https://angularfirebase.com/lessons/sharing-data-between-angular-components-four-methods/#data-service-ts
  • https://rangle.io/
  • https://angular.io/

Up Next
    Ebook Download
    View all
    Learn
    View all