Tuesday, April 9, 2024

Angular Custom Event Binding Using @Output Decorator

In the post Angular event binding we saw how event binding allows you to listen and respond to the events sent by the host elements. We can also bind a custom event of an Angular component that’s what we’ll see in this post how to bind custom event in Angular using @Output decorator.


Angular custom event binding

Using custom event binding is a great way for parent and child components to communicate where parent component is informed of any change in the child component. For example following statement in the parent template shows the event binding for the property "onUserSelected" in the child component.

Statement in parent component-

<app-user *ngFor="let user of users" 
            [usr]="user" (onUserSelected)="showUser($event)">

Property in child component-

@Output() onUserSelected: EventEmitter<User>;

@Output decorator, $event and EventEmitter

While doing a custom event binding in Angular three things you will come across are-

  1. @Output decorator
  2. EventEmitter class
  3. $event object

1. @Output decorator

A property in a Component that emits a custom event is decorated with @Output decorator. For example in the statement

@Output() onUserSelected: EventEmitter<User>;

onUserSelected is decorated with @Output() which means this property is going to emit a custom event. That is why this property is of type EventEmitter.

2. EventEmitter class

EventEmitter class is used in components with the @Output to emit custom events synchronously or asynchronously. EventEmitter maintains a list of subscribing instances and register handlers for the event.

EventEmitter class has two methods-

  • emit(value?: T)- Emits an event containing a given value, T signifies the value to emit.
  • subscribe()- Registers handlers for events emitted by this instance.

When we assign an EventEmitter to an output, subscription of instances is automatically done by Angular so you don't need to use this method explicitly in most of the scenarios.

3. $event object

In an event binding, Angular sets up an event handler for the target event. The binding conveys information about the event. This information is encapsulated in $event and may include data values such as an event object, string, or number.

When the event is raised, the handler executes the template statement. For example in the following statement

(onUserSelected)="showUser($event)"

(onUserSelected) is the target event

showUser($event) is the template statement.

When the event onUserSelected is raised, template statement, which in our example is showUser($event) method, is executed. Argument of the showUser() method is $event which encapsulates the value passed as method parameter.

Angular custom event binding example

We have got enough information about the event binding and the parts that form the custom event binding. Let’s create an example using that knowledge now. Note than example is created using Angular 17 and Bootstrap 5.

In the example there are two child components UserComponent and UserDataComponent and AppComponent is the parent component.

Initially list of user names is displayed (Done through UserComponent), on clicking any of the user User details are displayed (Done through UserDataComponent).

user.model.ts

In the Model class there are 3 fields name, age and joinDate.

export class User {
  name : string;
  age : number;
  joinDate : Date;
  constructor(name: string, age : number, joinDate : Date) {
    this.name = name;
    this.age = age;
    this.joinDate  = joinDate;
  }
}

app.component.ts (Parent component)

AppComponent uses User model so that is imported. An array of type User is defined and user instances are added to that array in the Constructor. Property selectedUser stores the value of the User which is selected and used to display details for the selected User. When the custom event is raised showUser() method gets called which assigns value to the selectedUser property.

import {Component} from '@angular/core';
import { User } from './user/user.model';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  users: User[];
  selectedUser!: User;
  constructor(){
    //Adding User instances to users array
    this.users = [new User('Jack', 56, new Date('2005-03-25')),
                  new User('Lisa', 32, new Date('2012-05-09')),
                  new User('Jayesh', 28, new Date('2014-10-21'))
                 ] ;
  }
  showUser(user: User) : void {
    // Setting selected user
    this.selectedUser = user;
  }
}

app.component.html

<div class="container">
  <h3>Click User to get details</h3>
  <app-user 
      *ngFor="let user of users" 
      [usr]="user" (onUserSelected)="showUser($event)">
  </app-user>

  <user-data *ngIf="selectedUser" [user]="selectedUser"></user-data>
</div>

Template has two selectors tags for the child templates. With in the <app-user> selector users array is iterated using ngFor directive and each user instance is bound to the usr property of the child component, onUserSelected is the output property (to emit event).

user.component.ts (Child component)

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { User } from './user.model';
@Component({
  selector: 'app-user',
  templateUrl: './user.component.html'
})
export class UserComponent {
  @Input() usr!: User;
  @Output() onUserSelected: EventEmitter<User>;
  constructor(){
    this.onUserSelected = new EventEmitter();
  }
  userClicked() : void{
    this.onUserSelected.emit(this.usr);
  }
}

In the child component usr variable is decorated with @Input decorator indicating that parent component can bind to this property.

onUserSelected is decorated with @Output indicating that it will emit an event.

In the userClicked() method using emit method an event is emitted with current user instance as event value which will be encapsulated in $event.

User.component.html

In the template user name is displayed, there is also an even binding for click event which calls the userClicked() method. Execution of userClicked() method results in emitting the event with the user instance as value.

<div class="row">
  <div class="col-xs-6">
    <label>Name:</label><span (click)='userClicked()'> {{ usr.name }}</span>
  </div>
</div>

userdata.component.ts (Child component)

import { 
  Component, Input
 } from '@angular/core';
import { User } from './user.model';
@Component({
  selector: 'user-data',
  templateUrl: './userdata.component.html'
})
export class UserDataComponent{
  @Input() user!: User;
}

Another child component UserDataComponent has a property user which is decorated with @Input decorator indicating that parent component can bind to this property. This is property to which selected user is assigned and then used to display user details.

userdata.component.html

This template shows the user details.

<div class="mt-4 p-3 bg-light">
  <h2>User Details</h2>
  <div class="row">
    <div class="col-xs-5 px-3">
      <label>Name: </label> {{ user.name }}      
    </div>
    <div class="col-xs-4 px-3">
      <label>Age: </label> {{ user.age }}
    </div>
    <div class="col-xs-4 px-3">
      <label>Joining Date: </label> {{ user.joinDate | date:'dd/MM/yyyy'}}
    </div>
  </div>
</div>

Testing the application

Initially user names are displayed.

Angular Custom Event Binding

When user name is clicked

Custom Event Binding Example

That's all for this topic Angular Custom Event Binding Using @Output Decorator. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Angular Tutorial Page


Related Topics

  1. Angular Custom Property Binding Using @Input Decorator
  2. Angular Custom Two-Way Data Binding
  3. Angular Style Binding With Examples
  4. Angular Example to Render Multiple Rows
  5. Angular @Input and @Output Example

You may also like-

  1. Angular ngClass Directive With Examples
  2. Angular @Component Decorator
  3. Service in Angular With Examples
  4. Angular Disable Button Example
  5. Multiple Catch Blocks in Java Exception Handling
  6. intern() Method in Java String
  7. Varargs (Variable-length Arguments) in Java
  8. Spring Batch Processing With List of Objects in batchUpdate() Method