Loading

Data sharing between the components in Angular

Data sharing between the components in Angular

In angular application, when we work with multiple components in a web page sometimes we need same set of data in two or more components. Rather than making api request on every component we can share data between the components very easily with the help of a simple technique called Data Sharing. In this artical I will explain all the possible ways of data sharing.

  • Parent to Child Data Sharing via Input
  • Child to Parent Data Sharing via Output() and EventEmitter
  • Child to Parent Data Sharing via ViewChild
  • Sharing Data Between Unrelated Components using Service

Let's discuss one by one in detail.

# Parent to Child Data Sharing via Input

parent.component.ts

import { Component } from '@angular/core';

@Component({
    selector: 'app-parent',
    template: `
        <app-child [childMsg]="parentMsg"></app-child>
    `,
    styleUrls: ['./parent.component.css']
})
export class ParentComponent{
    parentMsg = "Message from parent component"
    constructor() { }
}

child.component.ts

import { Component, Input } from '@angular/core';

@Component({
    selector: 'app-child',
    template: `
          Welcome to {{ childMsg }} in Angular
    `,
    styleUrls: ['./child.component.css']
})
export class ChildComponent {

    @Input() childMsg: string;

    constructor() { }

}

# Child to Parent Data Sharing via Output() and EventEmitter

Another most frequently used method of data sharing is via Output() and EventEmitter, where @Output() decorator becomes the output for the parent component and EventEmitter has the capability to propagate the event from child to parent component. Normally, this approach is used when we required to share the data based on an event triggered by user like button clicks or onChange or form entires etc.

In the child component, we have stored the EventEmitter instance into a messageEvent variable with the help of @Output() decorator to to send the message. Created sendMessage() to emit the data on a button click.

@Output() childToParent = new EventEmitter<String>();

In the parent component, we have created receiveMessage() to receive the messages and stored in a message variable.

child.component.ts

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
    selector: 'app-child',
    template: `
          <button (click)="sendMessage()">Send Message</button>
    `,
      styleUrls: ['./child.component.css']
})
export class ChildComponent {

    message: string = "Message from child"

    @Output() messageEvent = new EventEmitter<string>();

    constructor() { }

    sendMessage() {
        this.messageEvent.emit(this.message)
    }
}

parent.component.ts

import { Component } from '@angular/core';

@Component({
    selector: 'app-parent',
    template: `
        Message: {{message}}
        <app-child (messageEvent)="receiveMessage($event)"></app-child>
    `,
    styleUrls: ['./parent.component.css']
})
export class ParentComponent {

    constructor() { }

    message:string;

    receiveMessage($event) {
        this.message = $event
    }
}

You may also like: Angular: Bind event to dynamic created element

# Child to Parent Data Sharing via ViewChild

In this approach, we can share data from child to parent component using ViewChild decorator. ViewChild allows child component to be injected into the parent and it gives extra control to parent component to access the child events and properties. But we need to implement the ngAfterViewInit lifecycle hook in order to get the data from the child components.

child.component.ts

import { Component} from '@angular/core';

@Component({
    selector: 'app-child',
    template: `
    `,
    styleUrls: ['./child.component.css']
})
export class ChildComponent {

    childMsg = 'Message from Child';

    constructor() { }

}

parent.component.ts

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from "../child/child.component";

@Component({
    selector: 'app-parent',
    template: `
    Message: {{ message }}
        <app-child></app-child>
    `,
    styleUrls: ['./parent.component.css']
})
export class ParentComponent implements AfterViewInit {

    @ViewChild(ChildComponent) child;

    constructor() { }

    message:string;

    ngAfterViewInit() {
        this.message = this.child.childMsg
    }
}

# Sharing Data Between Unrelated Components using Service

When we don't have any direct relaction between the components like parent-child we use shared service to share data between the unrelated components or components from different modules or siblings etc.

In this approach, we create a service file and define BehaviorSubject to store the current value and the last value.

The main purposes of using BehaviorSubject are:

  • On subscription, it automatically return the latest value.
  • It always return the latest value by calling getValue() method. No need to call onnext, just create a set and get method in order to get value.

On the service file, to store the current value of the message we have taken a private BehaviorSubject and a variable to handle observable data which will be used in the components later. And finally, defined a method to call on the BehaviorSubject to change its value.

For sender and receiver components, we have injected shared service in the constructor, and then subscribe to the created observable variable in the shared service. Then finally set that value to a local variable. If any of these components changes the value of the local variable, the new value is automatically available to all other components.

shared.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable()
export class SharedService {

    private messageSource = new BehaviorSubject('default message here');
    currentMessage = this.messageSource.asObservable();

    constructor() { }

    changeMessage(message: string) {
        this.messageSource.next(message)
    }
}

sender.component.ts

import { Component, OnInit } from '@angular/core';
import { SharedService } from "../shared.service";
import { Subscription } from 'rxjs';

@Component({
    selector: 'app-sender',
    template: `
        {{message}}
    `,
    styleUrls: ['./sender.component.css']
})
export class SenderComponent implements OnInit, OnDestroy {

    message:string;
    subscription: Subscription;

    constructor(private sharedData: SharedService) { }

    ngOnInit() {
        this.subscription = this.sharedData.currentMessage.subscribe(message => this.message = message)
    }

    ngOnDestroy() {
        this.subscription.unsubscribe();
    }

}

receiver.component.ts

import { Component, OnInit } from '@angular/core';
import { SharedService } from "../shared.service";
import { Subscription } from 'rxjs';

@Component({
    selector: 'app-receiver',
    template: `
        {{message}}
        <button (click)="newMessage()">New Message</button>
    `,
    styleUrls: ['./receiver.component.css']
})
export class ReceiverComponent implements OnInit, OnDestroy {

    message:string;
    subscription: Subscription;

    constructor(private sharedData: SharedService) { }

    ngOnInit() {
        this.subscription = this.sharedData.currentMessage.subscribe(message => this.message = message)
    }

    ngOnDestroy() {
        this.subscription.unsubscribe();
    }

    newMessage() {
        this.sharedData.changeMessage("Message from Reveiver component")
    }

}

Thank you for visiting!!!

You may also like: How To Dockerize Angular Application With Nginx

Related Articles

Leave a Reply

Comments