SoFunction
Updated on 2025-04-11

Detailed explanation of new solutions for Angular inter-component communication

introduction

Among them, the first public dataService is used for communication between any component. DataService can use the angular service feature and the use of the registry to realize the sending and sending messages, without writing separate service logic.

background

Generally speaking, what are the existing communication methods between components in Angular?

Serial number Communication method describe
1 Input properties (@Input) Through property binding, data is passed from the parent component to the child component.
2 Output attribute (@Output) Through event binding, the child component can send events to the parent component and pass data.
3 Direct access to parent-child components In some cases, the parent component can directly access elements in a child component or template through the ViewChild or ContentChild decorator.
4 Service Create a shared service that components can inject to store and fetch data.
5 RxJS Subject and Observable Use Subject and Observable in RxJS to implement messaging between components.
6 Angular routing parameters Pass data between different components through routing parameters.
7 NgRx Use the NgRx state management library for more complex inter-component communication and data sharing.

However, the above methods have their limitations. Either there are many codes or the learning cost is high, especiallyCommunication across multiple components, for example from the following imageComponent DarriveComponent G, it is too cumbersome to use the first two methods. Methods 4 and 5 may be common solutions, but they are still a bit cumbersome-Need to write proprietary service code for each set of message passing

ComponentsA
       /      \
     ComponentsB      ComponentsC
    /   \      /    \
  ComponentsD ComponentsE ComponentsF  ComponentsG

The communication method introduced in this article is based on methods 4 and 5, and special abstraction is performed to implement a public dataService, which ultimately realizes that messages are received and sent without writing code for the intermediate links.

Common ways to realize message communication between components

For comparison, let me introduce the previous articleMethod 4+5Solution, this solution uses service and rxjs subject to achieve communication between arbitrary components.

First, we create aMessageServiceservice for passing messages between components:

// 
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
  providedIn: 'root',
})
export class MessageService {
  private messageSubject = new Subject<string>();
  // Observable string stream
  message$ = ();
  // Service method to send a message
  sendMessage(message: string) {
    (message);
  }
}

Next, we have two components,SenderComponentandReceiverComponentSenderComponentUsed to send messages, andReceiverComponentUsed to receive messages.

// 
import { Component } from '@angular/core';
import { MessageService } from './';
@Component({
  selector: 'app-sender',
  template: `
    &lt;input type="text" [(ngModel)]="message" /&gt;
    &lt;button (click)="sendMessage()"&gt;Send a message&lt;/button&gt;
  `,
})
export class SenderComponent {
  message: string;
  constructor(private messageService: MessageService) {}
  sendMessage() {
    ();
     = ''; // Clear the input box  }
}
// 
import { Component } from '@angular/core';
import { MessageService } from './';
@Component({
  selector: 'app-receiver',
  template: ` &lt;div&gt;Received message: {{ receivedMessage }}&lt;/div&gt; `,
})
export class ReceiverComponent {
  receivedMessage: string;
  constructor(private messageService: MessageService) {
    $.subscribe(message =&gt; {
       = message;
    });
  }
}

In this example, weMessageServiceCome to achieveSenderComponentTowardsReceiverComponentThe function of sending messages.MessageServiceRxJS is usedSubjectto create an observable message flow and thenSenderComponentCalled insendMessagemethod to send a message, and inReceiverComponentUsed insubscribeSubscribe to the message flow and receive the message.

Please note that in order to makeMessageServiceBecome a globally available singleton service, we@InjectableSet in the decoratorprovidedIn: 'root'. In this way,MessageServiceWill be a single instance shared by all components throughout the application.

To make the example work, don't forget toSenderComponentandReceiverComponentAdd to the module you belong to and place the corresponding component selector in the module's template.

so,SenderComponentThe sent message will passMessageServicePass toReceiverComponentand displayed inReceiverComponentmiddle. This completes an example of implementing inter-component message communication through a Subject of Service and RxJS.

New solutions

To understand this solution, you need to be familiar with Angular's service storage and data transfer principles and the multicast usage of rxjs by default.

The principle of this solution is to implement a service singleton feature (service is shared among components within the module) and the multicast feature of Subjectpublicservice, data transmission is realized through public service. Relatively, as in the previous articleAs shown in the file, the developer needs to create a service file for each group of communications and write the logic of the response separately.

Understand three key points of this plan:

Single caseBy@InjectableSettings in the decoratorprovidedIn: 'root', service becomes a single instance of all components shared in the entire application. Because it is shared, it can be used as a carrier of messages in communication. This is the fundamental premise of this plan.

multicast of rxjsThe basic principle is the observer mode (i.e., the publish subscription mode)

Registration formIn order to reuse the service and simplify the code, this solution introduces a registry to store the Subject object corresponding to each message event. Subject objects are created when creating a listener (where messages need to be received).

The service code is as follows:

// 
import { Injectable } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
@Injectable({
  providedIn: 'root',
})
export class DataService&lt;T&gt; {
  // Create a registry to store listeners  private events = new Map();
  /**
 * Send a message
 *
 * @param {string} event event.  Used to distinguish different monitors
 * @param {T} value Message content
 * @returns {void}
 * @memberof DataService
 */
  sendMessage(event: string, value: T): void {
    if (!(event)) {
      return;
    }
    (event).(value);
  }
  /**
 * Get the listener
 *
 * The listener is actually a rxjs Subject object that obtains data through subscription.
 *
    * Notice:
 * () should be before sendMessage(), otherwise the listener cannot be obtained from sendMessage() and the message cannot be sent.
 * () should be placed in lifecycle functions such as ngOnInit(), ngAfterViewInit(), etc. that will only be executed once.
 *
 * @param {string} event event.  Used to distinguish different monitors
 * @returns {Subject<T>}
 * @memberof DataService
 */
  getListener(event: string): Subject&lt;T&gt; {
    // This branch will be followed when listening in multiple places    if ((event)) {
      const current = (event);
      ++;
      return ;
    }
    const listener = {
      count: 1, // This field is used to record the number of listeners (subscribers)      subject: new Subject&lt;T&gt;(),
    };
    /**
 * Create a listener and add it to the registry
 *
 * The function is called when creating a listener (subscribe). The listener occurs before sending the message, so the listener is added to the registry here.
 */
    (event, listener);
    return ;
  }
  /**
 * Unsubscribe
 *
 * Must unsubscribe manually.
 * Check the number of listeners when canceling.  If there is no listener, remove the listener.
 *
 * @param {string} event
 * @param {Subscription} subscription
 * @returns
 * @memberof DataService
 */
  cancelSubscription(event: string, subscription: Subscription) {
    if (!(event)) {
      return;
    }
    const current = (event);
    --;
    if ( === 0) {
      // If there is no listener, remove the listener      (event);
    }
    ();
  }
}

When using it, just introduce the above public dataService and then directly call the API in the following example.

Example of creating a listener:

// Receive the passed messages  receiveChangeMessage;
  ngOnInit() {
    ...
     = ('event_name').subscribe(message =&gt; {
         = message;
      });
    ...
  }
  ngOnDestroy() {
    ('event_name', );
  }

Example of sending a message:

public onSomethingChange(value: boolean): void {

    ...

    ('event_name', value);
  }

Given a more complete example of usage

The following is a using theDataServiceExamples of implementing message communication between components:

Suppose we have two components:SenderComponentandReceiverComponentThey need to passDataServiceto deliver the message.

// 
import { Component } from '@angular/core';
import { DataService } from './';
@Component({
  selector: 'app-sender',
  template: `
    &lt;input type="text" [(ngModel)]="message" /&gt;
    &lt;button (click)="sendMessage()"&gt;Send a message&lt;/button&gt;
  `,
})
export class SenderComponent {
  message: string;
  constructor(private dataService: DataService&lt;string&gt;) {}
  sendMessage() {
    ('customEvent', );
     = ''; // Clear the input box  }
}
// 
import { Component, OnInit, OnDestroy } from '@angular/core';
import { DataService } from './';
import { Subscription } from 'rxjs';
@Component({
  selector: 'app-receiver',
  template: ` &lt;div&gt;Received message: {{ receivedMessage }}&lt;/div&gt; `,
})
export class ReceiverComponent implements OnInit, OnDestroy {
  receivedMessage: string;
  subscription: Subscription;
  constructor(private dataService: DataService&lt;string&gt;) {}
  ngOnInit() {
     = ('customEvent').subscribe(message =&gt; {
       = message;
    });
  }
  ngOnDestroy() {
    ('customEvent', );
  }
}

In this example, weDataServiceImplementedSenderComponentTowardsReceiverComponentThe function of sending messages.DataServiceofsendMessageThe method is used to send a message, andgetListenerMethods are used to subscribe to messages and update when messages are receivedReceiverComponentIn-housereceivedMessageproperty.cancelSubscriptionMethods are used to unsubscribe and remove listeners from the registry when there is no longer a listener.

Please make sure toSenderComponentandReceiverComponentAdd to the module you belong to and place the corresponding component selector in the module's template.

By usingDataServiceSenderComponentThe sent message will be passed toReceiverComponentand displayed inReceiverComponentmiddle. In this way, we successfully implement inter-component message communication.

Practical expansion

It can be made into a plug-in and called in the form of a decorator.

export class ReceiveComponent {
  @listen('messageEvent')
  message;
}

export class SendComponent {
  @send('messageEvent')
  message;
}

The above is the sharing of Qu Jinxiong. If you have more front-end technologies and want to communicate with us, please submit it. In addition, you are also welcome to participate in OpenTiny open source to build projects together and discuss front-end technologies together.

About OpenTiny

OpenTiny is an enterprise-level component library solution that is adapted to multiple ends such as PC/mobile, covering Vue2/Vue3/Angular multi-tech stacks, and has efficiency improvement tools such as theme configuration systems/middle and backend templates/CLI command lines, which can help developers to efficiently develop web applications.

Core highlights:

  • Cross-end and cross-framework: Use Renderless render-free component design architecture to implement a set of codes that support Vue2/Vue3, PC/Mobile at the same time, and supports function-level logic customization and full template replacement, with good flexibility and strong secondary development capabilities.
  • Component rich: There are 80+ components on the PC side and 30+ components on the mobile side, including high-frequency components Table, Tree, Select, etc., with built-in virtual scrolling to ensure a smooth experience in big data scenarios. In addition to common components in the industry, we also provide some unique and special components, such as: Split panel splitter, IpAddress IP address input box, Calendar calendar, Crop picture cropping, etc.
  • Configurable Components: The component supports two usage methods: template and configuration, which is suitable for low-code platforms. The team has integrated OpenTiny into the internal low-code platform and has made a lot of optimizations for low-code platforms.
  • The surrounding ecology is complete: Provides a TinyNG component library based on Angular + TypeScript, provides TinyPro mid- and back-end templates with 10+ practical functions and 20+ typical pages, provides TinyCLI engineering tools covering the entire process of front-end development, and provides a powerful online theme configuration platform. TinyTheme

The above is a detailed explanation of the new solution for communication between Angular components. For more information about communication between Angular components, please pay attention to my other related articles!