Angular 7中dispatch events用法及数据共享方案对比:Behavior Subject vs 自定义事件
Hey there! Let's walk through how to use dispatch events in Angular 7 first, then break down which data sharing approach is better: BehaviorSubject or global custom events via document.dispatchEvent().
Dispatch events in Angular 7 falls into two main use cases: triggering native DOM events and firing custom component events.
1. 触发原生DOM事件
Sometimes you need to simulate user interactions programmatically—like triggering an input event to update form controls, or a click event on a button. Here's how to do it:
// Inside your component class triggerInputUpdate() { const inputElement = document.getElementById('username-input') as HTMLInputElement; // Create and dispatch an input event (with bubble and cancelable flags enabled) inputElement.dispatchEvent(new Event('input', { bubbles: true, cancelable: true })); }
2. 触发组件级自定义事件
While Angular's @Output() decorator is the standard way for child-to-parent communication, you can also manually dispatch custom events from a component's DOM element. This is useful for edge cases where @Output() isn't feasible:
// Child component import { ElementRef, ViewChild } from '@angular/core'; @Component({ selector: 'app-notification', template: `<div #notificationContainer></div>` }) export class NotificationComponent { @ViewChild('notificationContainer') containerRef: ElementRef; sendNotification() { // Create a custom event with payload data const notifyEvent = new CustomEvent('new-notification', { detail: { message: 'Your order is ready!', type: 'success' }, bubbles: true, cancelable: true }); // Dispatch the event from the component's DOM element this.containerRef.nativeElement.dispatchEvent(notifyEvent); } } // Parent component template (listen for the custom event) <app-notification (new-notification)="handleNotification($event)"></app-notification> // Parent component class handleNotification(event: CustomEvent) { console.log(`Received ${event.detail.type} notification: ${event.detail.message}`); }
Now let's compare these two popular approaches for cross-component data sharing in Angular 7.
What is BehaviorSubject?
BehaviorSubject is a type of RxJS Subject that stores the current "latest" value. When a new subscriber joins, it immediately gets this current value—perfect for state management scenarios where components need to know the initial state. It's typically wrapped in an Angular service for global access.
Example Implementation:
// shared-data.service.ts import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class SharedDataService { // Initialize with a default value private userStatusSubject = new BehaviorSubject<{ isLoggedIn: boolean; username: string }>({ isLoggedIn: false, username: '' }); // Expose as an observable to prevent direct modification public userStatus$ = this.userStatusSubject.asObservable(); updateUserStatus(isLoggedIn: boolean, username: string) { this.userStatusSubject.next({ isLoggedIn, username }); } } // Component A (updates data) constructor(private dataService: SharedDataService) {} loginUser(username: string) { this.dataService.updateUserStatus(true, username); } // Component B (subscribes to data) constructor(private dataService: SharedDataService) {} ngOnInit() { // Gets the initial value immediately, then updates on changes this.dataService.userStatus$.subscribe(status => { if (status.isLoggedIn) { console.log(`Welcome back, ${status.username}!`); } else { console.log('Please log in.'); } }); }
What is document.dispatchEvent?
This approach uses the global document object to fire custom events that any component can listen to. It leverages the DOM event bubbling system to achieve global communication, but it's not tailored to Angular's architecture.
Example Implementation:
// Component that sends the event sendGlobalAlert() { const alertEvent = new CustomEvent('global-alert', { detail: { text: 'System maintenance scheduled tonight!', priority: 'high' }, bubbles: true, cancelable: true }); document.dispatchEvent(alertEvent); } // Component that listens for the event private alertHandler!: (event: CustomEvent) => void; ngOnInit() { this.alertHandler = (event: CustomEvent) => { console.log(`[${event.detail.priority}] Alert: ${event.detail.text}`); }; document.addEventListener('global-alert', this.alertHandler); } // Critical: Clean up the listener to avoid memory leaks ngOnDestroy() { document.removeEventListener('global-alert', this.alertHandler); }
Head-to-Head Comparison
1. Type Safety
- BehaviorSubject: Fully supports TypeScript's type checking. You define the data type upfront (e.g.,
BehaviorSubject<User>), so subscribers always get typed data—no guesswork or type assertions needed. - document.dispatchEvent: The
detailpayload is of typeany, so you have to manually cast it to the correct type. This increases the risk of type mismatches and runtime errors.
2. Memory Leak Risk
- BehaviorSubject: Easy to manage with RxJS tools like the
asyncpipe (which auto-unsubscribes when the component is destroyed) ortakeUntiloperators. Memory leaks are rare if you follow best practices. - document.dispatchEvent: Requires manual cleanup of event listeners in
ngOnDestroy. Forgetting to remove listeners will leave them attached to the document even after the component is destroyed, leading to memory leaks over time.
3. Scope & Control
- BehaviorSubject: Encapsulated in an Angular service, so you can control access (e.g., make the
next()method private to restrict who can update data). It aligns with Angular's modular architecture and avoids global scope pollution. - document.dispatchEvent: Events are global—any component can listen or fire them. There's no built-in way to restrict access, and event name collisions are a real risk (e.g., two components using the same event name for different purposes).
4. Data Persistence & Initial Values
- BehaviorSubject: Stores the latest value, so new components get the current state immediately when they subscribe. Ideal for state that needs to persist across component loads (like user login status).
- document.dispatchEvent: Events are one-time broadcasts. New components won't receive past events unless you manually re-trigger them—bad for scenarios where components need to know the initial state.
5. Performance
- BehaviorSubject: Built on RxJS's efficient observer pattern. Subscriptions and value emissions are lightweight, making it great for high-frequency updates (like real-time data).
- document.dispatchEvent: DOM events involve event propagation through the DOM tree, which adds overhead. Firing events frequently can lead to performance issues in complex applications.
Which Should You Choose?
- Prioritize BehaviorSubject: For almost all Angular-specific data sharing needs—user state, theme preferences, route data, etc. It's type-safe, maintainable, and fits seamlessly into Angular's ecosystem.
- Use document.dispatchEvent sparingly: Only when you need to communicate with non-Angular code (like vanilla JS plugins) or for one-off, simple global notifications. Avoid using it as your primary data sharing strategy.
内容的提问来源于stack exchange,提问作者Santhosh

