In Angular, components can communicate with each other by raising events. For example, when a user clicks a button inside a component, you might want to notify its parent component about that action.
To do that, Angular allows us to define custom events using the @Output decorator and EventEmitter (old way) or the output() function (new way).
This enables you to create events that can be emitted and handled by parent components, similar to native DOM events.
Old Way: Using @Output and EventEmitter
The traditional approach is as follows:
- You define an event using the @Output decorator and an instance of EventEmitter.
- You emit the event using .emit().
New Way: Using the output Function
Now, Angular introduces a simplified syntax to define custom events without needing EventEmitter.
Instead of using @Output() and EventEmitter, you can use the output() function directly.
The newer approach eliminates the need to explicitly instantiate an EventEmitter, which simplifies code and reduces boilerplate.
Even though the syntax is different, the behavior is exactly the same as the old approach. You still emit events, pass data with them, and listen for them from the parent component.
Basic Setup
To create a custom event, you define a property in your component using the output function, which returns an OutputEmitterRef.
import { Component, output } from '@angular/core';
@Component({
selector: 'child-component',
template: `<button (click)="sendData()">Click Me</button>`,
})
export class ChildComponent {
dataSent = output<string>(); // No need to import EventEmitter
sendData() {
this.dataSent.emit('Hello, Parent!');
}
}
In this case, the output function does exactly what EventEmitter did, but in a more compact form.
Whether you’re using the old or new way, the way you listen for the event in the parent component is the same.
In the parent component, you can listen for the dataSent event using the regular event binding syntax (eventName) and call a method when the event is triggered.
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
template: `
<h1>Parent Component</h1>
<child-component (dataSent)="receiveData($event)"></child-component>
<p>{{ receivedMessage }}</p>
`,
})
export class ParentComponent {
receivedMessage: string = '';
// Method to handle the received data from the child component
receiveData(message: string) {
this.receivedMessage = message; // Store the message received from the child
}
}
Customizing Output Names
You can specify a custom name for the event in the template using the alias option
changed = output({alias: 'valueChanged'});
· The alias option only affects how the event is referenced in the template, not in TypeScript code.
· In the TypeScript code, the original name of the output property is used (in this case, changed).
· In the template, the alias name valueChanged is used to listen for the event.
Subscribing to Outputs Programmatically
When dynamically creating components in Angular, you might want to listen for events emitted by the component, for example, when a button inside the dynamically created component is clicked.
You can do this by subscribing to their output events programmatically using subscribe.
After creating the dynamic component in the parent component, we can subscribe to its event property to listen for it.
When the event is emitted, the subscription in the parent component’s code will receive the emitted data and can take an action based on it, such as logging it to the console, updating the UI, or performing some other logic.
const componentRef = viewContainerRef.createComponent(SomeComponent);
// Subscribe to the dynamically created component's output event
componentRef.instance.someEventProperty.subscribe((eventData) => {
console.log(eventData);
});
You can also unsubscribe manually:
const eventSubscription = componentRef.instance.someEventProperty.subscribe(eventData => {
console.log(eventData);
});
eventSubscription.unsubscribe();
Key Points about Custom Events
Custom events do not bubble: In native DOM events, when an event is triggered, it can propagate up from the target element to its ancestors, allowing parent elements to listen for events on child elements. However, custom events in Angular do not bubble.
Case sensitivity: Output names are case-sensitive.
Inheritance: When a component extends another, it inherits the outputs from the parent component. This means child component automatically inherits the output (custom event) from the parent and can listen to or trigger it without needing to redefine the event.
Event names: Choose event names carefully to avoid conflicts with native DOM event names like click, focus, etc.
Conclusion
In conclusion, Angular provides two approaches for component communication through custom events: the traditional method using @Output() and EventEmitter, and the newer, simpler output() function. The newer approach eliminates the need for importing EventEmitter and reduces boilerplate code, making the code more concise and easier to maintain.
Check out my deep dives on → Gumroad
Top comments (0)