DEV Community

Muhammad Muhktar Musa
Muhammad Muhktar Musa

Posted on

Event Handling in Angular

Understanding event and event handling is a key to understanding angular..
Angular always looks to see if the name in a DOM matches any event property of a known directive or not. We are going to have a look at
event and event handling, custom events with event emitter, structural directives , two way binding, input and output decorators.

Event and Event Handling

in an event binding, angular sets out an event handler for the target event. When the event is raised, the handler executes the template statement
the template statement typically involves a receiver which performs an action in response to the event. This event could be like storing values
from the html control into a model.
The binding conveys information about the event. This information can include data values such as event objects, string or number named $event
The target event determines the shape of the $event object. If the target event is a native DOM element event, then $event is a DOM event object with properties such as target and target.value
Let us take a look at an example

<input [value] ="currentItem.name"
 (input) = "currentItem.name = $event.target.value">
Enter fullscreen mode Exit fullscreen mode

without ngModel
The code sets the value property by binding to the name property. To listen for changes to the value, the code binds to the input event of the element.
When the user makes changes the input event is raised and the binding executes the statement within a context that includes the DOM event
object ($event)

Custom events with event emitter

In angular, directives typically raise custom events with an angular EventEmitter.
example

<img src="{{itemImageUrl}}" [style.display]="displayNone">
<span>{{item.name}}</span>
<button (click)="delete()">Delete</button>
Enter fullscreen mode Exit fullscreen mode

on the ts file

 @Output() deleteRequest = new EventEmitter<item>();
  delete() {
    this.deleteRequest.emit(this.item);
  }
Enter fullscreen mode Exit fullscreen mode

The component defines a deleteRequest property that returns an EventEmitter. When the user clicks delete, the componentinvokes the delete()
method. The component tells the EventEmitter to emit an object.
Imagine hosting a parent component that binds to the deleteRequest event of the above component.

<app-messages (deleteRequest)="deleteItem($event)" [item]="currentItem"></app-messages>
Enter fullscreen mode Exit fullscreen mode

When the delete request event fires, angular calls the parent components deleteItem() method. It passes the item to the delete in the $event variable.

Structural Directives

Structural directives are directives that can add or remove an element from the DOM. we have several structural directives.
Let us take a look at them

*ngIf

An element can be added or removed from the DOM by adding an *ngIf to a host component. The directive is binded to a conditional expression

<app-messages *ngIf="isActive" [item]="item"></app-messages>
Enter fullscreen mode Exit fullscreen mode

Do not forget the star sign. It is a vital part of this structural directives. In the above code, when the isActive expression returns a truthy value, *ngIf adds the component to the DOM. When the expression is falsy, *ngIf removes the component from the DOM destroying the component
and all its sub component.

*ngFor

It is a repeater directive. It presents us with a way to present a list of items. Let us take a look at an example
Define a block of html that defines how a single item should be displayed. Tell angular to use that block as a template for rendering each item in the list.

<div *ngFor="let item of items">{{item.name}}</div>

Enter fullscreen mode Exit fullscreen mode

The string "let item of items" means take each items in the items array, store it in the local item looping variable and make it available
to the templated html for each iteration.

Template reference variable (#var)

This a template variable often depicted with the symbol #. It is often a reference to a DOM element within a template. It can also refer
to a directive which contains a component, an element, a TemplateRef or a web component. To declare this template variable/reference variable, the symbol # is used.

<input type="text" class="form-control ng-untouched ng-pristine ng-valid" id="name"
  #name="ngModel"
         required
         [(ngModel)]="model.name" name="name">
Enter fullscreen mode Exit fullscreen mode

The #name in the input element refers to a template variable called name that is binded in a two way by the ngModel. You can refer to the template variable anywhere in the template component further down the template.

<input type="text" class="form-control ng-untouched ng-pristine ng-valid" id="name"
  #phone  placeHolder ="Phone number"/>

  <! --lots of other elements -->


<button type="button" class="btn btn-default" (click)="cellPhone(phone.value)">Call</button>
Enter fullscreen mode Exit fullscreen mode

##### @Input() and @Output() properties
This two properties allow angular to share data between the parent content and the child directives or components. The major difference between them is that the @Input() property is writeable while the @Output() property is observable. For example

 <parent-component>
    <child-component></child-component>
</parent-component>
Enter fullscreen mode Exit fullscreen mode

The @Input() and @Output() properties will act as the api for the child component in that they allow the child component to communicate with the parent component. @Input() allows data to flow into the child component while @Output() allows data to flow out of the child component. The @Input() and @Output() properties are independent of each other. If the child component needs to send only data to the parent component, an @Output() property is needed. If the child component needs to receive data from the parent component an @Input() property is needed.
The @Input() property is used in a component or directive to let angular know that a property in that component can receive its value from the its parent component i.e data flows from parent to child.
@Output() marks the property in a child component as a doorway through which data can travel from the child to the parent. The child component then has to raise an event so that the parent component knows that something has changed. @Output() works hand in hand with the EventEmitter to emit custom events.
Lets us take a look at an example
In the child component class

import {Output, EventEmitter} from '@angular/core'
Enter fullscreen mode Exit fullscreen mode

decorate a property with @Output() in the child component class

 export class myFormComponent {

  @Output()  newItemEvent = new EventEmitter<string>();
addNewItem(value: string) {
  this.newItemEvent.emit(value)
}
 powers = ['Really smart', 'Flexible','Super hot', 'Weather changer'];

}
Enter fullscreen mode Exit fullscreen mode

in the child HTML template, add

 <label> Add an Item <input #newItem/></label>
 <button (click)="addNewItem(newItem.value)"> Add to parent list</button>
Enter fullscreen mode Exit fullscreen mode

in the parent component

 export class AppComponent {


  items = ['Really smart', 'Flexible', 'Super hot', 'Weather changer'];

  addItem(newItem: string) {
    this.items.push(newItem);
  }
}
Enter fullscreen mode Exit fullscreen mode

and in the parent HTML component add

<app-item-output (newItemEvent)="addItem($event)"></app-item-output>
Enter fullscreen mode Exit fullscreen mode

The event binding (newItemEvent)="addItem($event)", tells angular to connect the event in the child newItemEvent to the method in the parent addItem(); and that the event the child component is notifying about is to be the argument of addItem();. The $event contains the data that the user types into the in the child template user interface.
For the @output property to come into effect we add a structural directive to the parent template

<ul>
    <li *ngFor = "let item of items">{{item}}</li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)