Emit and handle events

web
mobile

Author: Dawid Adach

-

Currently, our Event component displays an icon that is supposed to delete the item from the list. As you already know, the list of the Events is held in the parent component - App. Therefore, it's not possible for the Event component to delete itself.

In order to delete an event from a list, we have to pass a call from the child component (Event) to its parent component (App). In this lesson, we will learn how to pass function calls between components.

Before we start to that, let's work on an App template first:

1. App template

1.1. Style

We don't need styles anymore, let's remove them from app.component.scss.

1.2. Template

Update app.component.html file with the following template:


  <div class="container">
    <div class="row mt-3">
      <div class="col-md-9">
        <div *ngFor="let event of events">
          <app-event [value]="event"></app-event>
        </div>
        <div class="text-center">
          <a
            type="button"
            mdbBtn
            color="info"
            class="waves-effect mb-4"
            mdbWavesEffect
            >Add event
          </a>
        </div>
      </div>
      <div class="col-md-3">
        <h3 class="text-uppercase my-3">Schedule</h3>
        <h6 class="my-3">
          It's going to be busy that today. You have
          <b> {{ events.length }} events </b> today.
        </h6>
        <h1 class="my-3">
          <div class="row">
            <div class="col-3 text-center">
              <mdb-icon fas icon="sun"></mdb-icon>
            </div>
            <div class="col-9 ">Sunny</div>
          </div>
          <div class="row">
            <div class="col-3 text-center">
              <mdb-icon fas icon="thermometer-three-quarters"></mdb-icon>
            </div>
            <div class="col-3 ">23°C</div>
          </div>
        </h1>
        <p>
          Don't forget your sunglasses. Today will dry and sunny, becoming warm
          in the afternoon with temperatures of between 20 and 25 degrees.
        </p>
      </div>
    </div>
  </div>
  

List of changes:

  • Added an "Add event" button
  • Added an event counter ({{ events.length }}) in the right-hand column
  • Added static (Weather Forecast) content to the right-hand column
  • Added some minor classes to enhance spacing

Preview:

Preview

Note:
In the right-hand column, we added an Event counter which tells us how many events are scheduled for today. In order to get this number we are simply counting elements within the array using the {{events.length}} function.


2. Delete Event function

Now we can create a function which removes a particular Event from an array. It's a very simple function, it looks for the index of the clicked item, and removes it from the events array[] using the splice() function.

Add the following function to the AppComponent class within the app.component.ts file


  deleteEvent(event: any) {
    const itemIndex = this.events.findIndex(el => el === event);
    this.events.splice(itemIndex, 1);
  }  	
  

Note:
The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. In our case we are checking whether the item (event) that we are about to delete is one of the items (el) in the array, and return it's position.

Now when our function is ready, we can emit an event from the Event component.

3. Handle click event

  1. Add a new function to the EventComponent class within the event.component.ts file.
  2. 
      handleDeleteClick() {
        console.log("Delete button clicked!");
      } 	
      
  3. Update the mdb-badge in event.component.html
  4. 
        <mdb-badge (click)="handleDeleteClick()" danger="true" class="text-center float-right">-</mdb-badge>    
      
  5. Test it. Run the app, open the developers console and click on the delete icon. You should see a confirmation message in the console.
  6. Clicked event

4. Event emitting

In order to call the parent (App) component's deleteEvent() function from the child (Event) component we have to emit an Event from one component and catch it in another.

Warning:
The naming might be a little bit confusing. This is because we have a component within our app which we called an Event. This Event represents a single entry in our agenda (we could have called it Item, Appointment or Entry).

At the same time, Angular uses Event to call JavaScript-like events. This Event refers to an "occurrence" to which JavaScript can react.

Since this may be a bit confusing I will use different styles and whenever we refer to Event Component, I will use a yellow highlight, while whenever I refer to an Angular Event, I will use a red font.

Whenever we want to emit an Event, we have to import EventEmmiter first. Since we will be transferring outside the component, we also have to import an Output directive.

  1. Import EventEmmiter and Output in event.components.ts
  2. 
        <mdb-badge (click)="handleDeleteClick()" danger="true" class="text-center float-right">-</mdb-badge>    
      

    Note:
    In a previous lesson we were passing data to (inside) our component, in order to do that we had to use an Input directive.

    Now, since we are passing data out (outside) of our component, we have to use Output directive.

  3. Define the @Output() within the EventComponent class.
  4. 
      @Output() deleteEventInstanceEvent: EventEmitter<any> = new EventEmitter<any>();
      

    Note:
    We called the Output deleteEventInstanceEvent to make it clear that we are emitting and Event to delete the instance of Event.

    You can read the name as deleteEventInstanceEvent().

    If we could call our calendar entry differently, i.e. Appointment, we could simply call this function deleteAppointmentEvent without using the extra Instance word.

  5. Update the handleDeleteClick() method with the following code:
  6. 
      handleDeleteClick() {
        this.deleteEventInstanceEvent.emit(this.value);
      }
      

    This how your event.component.ts file should look like:

    
    import {Component, EventEmitter, Input, Output} from '@angular/core';
    
    @Component({
      selector: 'app-event',
      templateUrl: './event.component.html',
    })
    export class EventComponent {
      @Input() value: any;
      @Output() deleteEventInstanceEvent: EventEmitter<any> = new EventEmitter<any>();
    
    
      handleDeleteClick() {
        this.deleteEventInstanceEvent.emit(this.value);
      }
    }
    
      

    Now whenever the user clicks on the delete icon, next to the Event title, it will emit a new event and pass itself (an object) as a parameter.

4. Catching & handling events

The last thing we have to do is to catch an emitted event from the Event component.

In order to that let's update our <app-event> tag in app.component.html:


        <app-event [value]="event" (deleteEventInstanceEvent)="deleteEvent($event)"></app-event>

  

As you probably guessed, we have bound here the emitted event (deleteEventInstanceEvent) with the internal App component's function - deleteEvent() and we are passing.

In other words - we are telling Angular that he can expect that <app-event> can emit events and which function do we want to use to handle it.

Delete Events

Now, whenever we click on a delete icon:

  1. The sser clicks on the delete icon
  2. (click) calls the handleDeleteClick() function
  3. handleDeleteClick() emits a deleteEventInstanceEvent event
  4. The App component catches it and triggers deleteEvent()
  5. Finally deleteEvent() deletes the corresponding element from the array

Flow

Rate this lesson

Previous lesson Next lesson

Spread the word:
Do you need help? Use our support forum

About the author

Dawid Adach
For more than 5 years Dawid worked as an IT Consultant specializing in SOA/EAI/ESB in the banking domain. He gained experience working in countries like Netherlands, Belgium, Poland and India developing enterprise-class systems for the most prestigious companies. Since co-founding mdbootstrap.com & brandflow.net in 2016 he has been using and teaching technologies such as Angular, TypeScript, PHP, AJAX, Mongo, SQL, Hadoop Stack, Virtualization, Automation and many others...