What is the difference between passing a method in property binding in Angular vs @Output() and EventEmitter?

482 Views Asked by At

Let's say I have a pair of parent-child components in Angular as follows:

Child component class:

export class ChildComponent {
   @Input() addTask:any;
}

Child component template:

<button (click)="addTask('cleaning')">Add Task</button>

Parent component class:

export class ParentComponent {

   newTask:string;

   add(task:string){
    this.newTask = task;
   }
}

Parent component template:

<div>
   <app-child [addTask]="add.bind(this)"></app-child>
</div>

Here, I am passing a string from the child to the parent by passing the parent method to the child using property binding. I have read that this is okay as long as the method is not having side-effects. Let's assume my method is not having any side-effects. But my question is, how is it different from using @Output() and EventEmitter? The above functionality can be re-written using @Output() and EventEmitter as follows:

Child component class:

export class ChildComponent {
   @Output() newEvent = new EventEmitter<string>();
   
   addTask(task:string){
    this.newEvent.emit(task);
   }
}

Child component template:

<button (click)="addTask('cleaning')">Add Task</button>

Parent component class:

export class ParentComponent {

   newTask:string;

   add(task:string){
    this.newTask = task;
   }
}

Parent component template:

<div>
   <app-child (newEvent)="add($event)"></app-child>
</div>

Both these approaches do the same thing. Please let me know what is the difference between these two approaches assuming my method is not having any side effects. Also I want to know which is the better approach and why.

3

There are 3 best solutions below

1
slashbrackets On

In Angular, passing a method in property binding allows a component to pass a reference to a method defined in its parent component to one of its child components. This can be done using the square bracket syntax in the parent template and a corresponding input property in the child component class.

On the other hand, @Output() and EventEmitter in Angular provide a way for a child component to emit events to its parent component. This can be done by defining an event property in the child component class using the @Output() decorator, and emitting events using the EventEmitter class.

The main difference between these two approaches is that property binding with a method reference is a one-way communication from parent to child, whereas @Output() and EventEmitter provide a way for child components to emit events to their parent components. This makes @Output() and EventEmitter a more flexible and powerful mechanism for handling events in Angular applications, as it allows for bidirectional communication between components.

0
Bennison J On

@Input()

  • By default, all properties of components are only accessible inside these components. not from outside.
  • Using the @Input() decorator, we can expose a property to all other parent components. this is how we can use the component property in property binding.

@Output()

  • To pass data from the child to the parent we need to use the event emitter. an event emitter is an object which allows us to emit our event.
  • In step one, we need to create an object from the event emitter constructor function. Here, the important thing is using the @Output() decorator to make that property available for the parent components. Then only parents know when the new event is emitted.
  • In step two we need to make available the event emitter object from the child to that parent component. to do that need to use @Output() decorator. this is the way to pass the data from child to parent.
  • What the parent component does is, whenever a new event is emitted, then the parent component knows and reacts to that event. this is also known as custom event binding.
0
Piyali On

This is proper way for parent child

app.component.html

 <div>
  <!-- newTask is a variable which is passing through @Input parameter task-->
  <app-child [task]="newTask" (newEvent)="add($event)"></app-child>
</div>

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  newTask: string;
  constructor() {
    this.newTask = 'build';
  }
  add(task: string) {
    this.newTask = task;
    console.log('newTask => ', this.newTask);
  }
}

child.component.ts

import {
  Component,
  SimpleChanges,
  OnChanges,
  Input,
  Output,
  EventEmitter,
} from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
  <button (click)="addTask('cleaning')">Add Task</button>
  `,
})
export class ChildComponent implements OnChanges {
  @Input() task: any;
  @Output() newEvent = new EventEmitter<string>();

  constructor() {}

  ngOnChanges(changes: SimpleChanges) {
    console.log('task => ', this.task);
  }

  addTask(task: string) {
    this.newEvent.emit(task);
  }
}