[Fixed] @Output and @HostListener click causes Maximum call stack size exceeded when named the same

Issue

When having an @Output named click, and having a @HostListener listening for click, is it possible to make it so that a Maximum call stack size exceeded error doesn’t occur? I would like to keep the output value as click, as I already know that I can just rename the output name and it will work.

I have tried e.stopPropagation(), but that just gives me an error saying that stopPropagation is not a function.

I have a component that looks like this. It has an incoming click listener and an outgoing click emitter:

@Component({
  selector: 'my-button',
  template: `
    <button>{{label}}</button>
  `
})
export class Button {
  @Input() label = '';
  @Input() uri?: string;
  @Output('click') onButtonClick = new EventEmitter<string>();

  @HostListener('click')
  onClick() {
    if (this.uri) {
      this.onButtonClick.emit(this.uri);
    }
  }
}

I am then using it like this:

<my-button label="Google" uri="http://google.com" (click)="doSomething()"></my-button>

Here is a Stackblitz

Solution

You can add a condition like:

@HostListener("click", ['$event'])
onClick(e) {
  if (this.uri && e !== this.uri) {
    this.onButtonClick.emit(this.uri);
  }
}

It will be still emitted twice and you need to handle it in your parent component.

Another way is to remove

@Output('click') onButtonClick = new EventEmitter<string>();

and pass data through event object:

@HostListener("click", ['$event'])
onClick(e) {
  if (this.uri) {
    e.data = this.uri;
  }
}

parent.html

(click)="doSomething($event)"

parent.ts

doSomething(e) {
  console.log(e.data);
}

Forked Stackblitz

Leave a Reply

(*) Required, Your email will not be published