Pass Data Between Siblings in Angular

In Angular, components are the building blocks of the user interface. If the structure of components is hierarchical, passing data between parent and child components is simple using input/output bindings. However, passing data directly between sibling components can be more challenging since they don’t have a direct parent-child relationship.

Table of Content

  • Using Shared Service
  • Using Input and Output Properties
  • Using State Management (NgRx or Redux)

“Passing data between siblings” refers to the process of sharing data between components that share the same parent component but are not directly connected. It involves establishing a communication mechanism between the sibling components so that they can exchange information. Let us discuss a few approaches to achieving this.

Using Shared Service

One approach is to create a shared service that acts as an intermediary between the sibling components. The shared service holds the data and exposes methods to update and retrieve the data. The sibling components can inject the shared service and communicate with each other by setting and getting the shared data. The service can store data that can be accessed and modified by both sibling components.

This approach is useful when the sibling components need to share data without relying on parent-child relationships or event emitters. Additionally, it promotes code reusability since the same shared service can be used across different parts of the application where data sharing is required.

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

@Injectable({
providedIn: 'root'
})
export class SharedService {
sharedData: any;
constructor() { }
setData(data: any) {
this.sharedData = data;
}
getData(): any {
return this.sharedData;
}
}

In Sibling A component, we can set the shared data using the shared service’s setData() method. In Sibling B component, we can retrieve the shared data using the shared service’s getData() method.

Using Input and Output Properties

This approach involves using Input and Output properties to establish communication between sibling components. The parent component acts as an intermediary and passes data from one sibling component to another using property bindings. In this approach , Sibling A component, emit an event with the data to be passed. This event will be captured by the parent component.In the parent component, we listen for the emitted event from Sibling A and capture and store the data. This will pass the data to Sibling B.In Sibling B component, define an input property to receive the data from the parent component. The input property will automatically be updated with the data passed from the parent component.

Using State Management (NgRx or Redux)

State management libraries like NgRx or Redux provide a centralized store to manage application state. Sibling components can dispatch actions to update the store, and the updated data can be accessed by any component that subscribes to the store. This approach is more suitable for complex applications with a large amount of shared state.In Component A, when we want to pass data to Component B, we dispatch an action, and include the data as part of the action payload. In Component B, we can subscribe to the relevant portion of the state using NgRx’s select operator or selectors. This allows Component B to receive updates whenever the shared data changes.

Steps to Pass Data between Siblings

Let us take an example to understand any of the above approach.

Step 1: Install the Angular CLI using the following command

npm install -g @angular/cli

Step 2: Create a new Angular Project

ng new new-project
cd new-project

Dependencies

"dependencies": {
"@angular/animations": "^17.3.0",
"@angular/common": "^17.3.0",
"@angular/compiler": "^17.3.0",
"@angular/core": "^17.3.0",
"@angular/forms": "^17.3.0",
"@angular/platform-browser": "^17.3.0",
"@angular/platform-browser-dynamic": "^17.3.0",
"@angular/router": "^17.3.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
}

Step 3: To start the application run the following command.

ng serve

Step 4: Let us create two components

ng g component sibling1
ng g component sibling2

Step 5: Let us create a shared service for data passing

ng g service shared

Project Structure:

Folder Structure

Step 6: Implementing the code

HTML
<!-- sibling1.component.html -->
<input type="text" [(ngModel)]="message" />
<button (click)="sendMessage()">Send Message</button>
HTML
<!-- sibling2.component.html -->

Message from Sibling Component : {{ message }}
HTML
<!-- app.component.html -->
<div>
    <app-sibling1></app-sibling1>
    <app-sibling2></app-sibling2>
</div>
JavaScript
//sibling1.component.ts

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

@Component({
    selector: 'app-sibling1',
    templateUrl: './sibling1.component.html',
    styleUrls: ['./sibling1.component.scss'],
})
export class Sibling1Component implements OnInit {
    constructor(private sharedService: SharedService) { }
    message: string = '';
    ngOnInit(): void { }
    sendMessage() {
        this.sharedService.setData(this.message);
    }
}
JavaScript
//sibling2.component.ts

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

@Component({
    selector: 'app-sibling2',
    templateUrl: './sibling2.component.html',
    styleUrls: ['./sibling2.component.scss'],
})
export class Sibling2Component implements OnInit {
    constructor(private sharedService: SharedService) {
        this.sharedService.data$.subscribe((data) => {
            this.message = data;
        });
    }
    message: string = '';
    ngOnInit(): void { }
}
JavaScript
//shared.service.ts

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

@Injectable({
    providedIn: 'root',
})
export class SharedService {
    private dataSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
    public data$: Observable<any> = this.dataSubject.asObservable();

    constructor() { }

    setData(data: any) {
        this.dataSubject.next(data);
    }
}

Output:

Pass Data Between Siblings in Angular.

In the above example, we have created a shared service file, to set the data using a BehaviorSubject to hold the data and an Observable to allow components to subscribe to changes in the data. This file helps us in sharing data between sibling components in Angular. Here, In the Receiver Component, we subscribe to the data$ observable provided by the SharedService. Whenever a new message is sent, the subscribe() callback is triggered, and we update the message property.