2

A lot is written about this problem, but all answers suggests one or more of the following:

  • stopPropagation
  • preventDefault
  • return false.

But non is working in my case. Here is stackblitz. When button is clicked, desired behaviour is that console shows:

click - button
stop

but it also shows

Click from app component - but it shouldn't happened

This click shouldn't happen (in app.component):

<my-button [disabled]="true" (click)="onClick()"></my-button>`

public onClick()
{
  console.log("Click from app component - but it shouldn't happened");
}

One solution is provided here. But, is creating another span element. Is this really the only option?

Also

native add and remove EventListeners

doesn't looks as elegant solution.

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
Makla
  • 9,899
  • 16
  • 72
  • 142

3 Answers3

4

Remove the HostListener and add a click listener for the button in my-button component.

Plus, you don't need the additional this.click.emit() since it's automatically going to propagate if stopPropogation is not called.

Template

<button (click)='onClick($event)'>{{text}}</button>

When the button is clicked, the onClick in my-button is called, based on some logic you can either choose to emit or discard the click.

@Component({
  selector: "my-button",
  template: `<button (click)='onClick($event)'>{{text}}</button>`
})
export class MyButton
{
  @Input() disabled = false;

  @Input() text = "Click me";
  @Output() click = new EventEmitter();

    public onClick(event: Event)
    {
        console.log("click - button");
        if (!this.disabled)
            console.log("click emit");
        else
        {
            console.log("stop");
            event.stopPropagation();
        }
    }
}

Stackblitz

cyberpirate92
  • 3,076
  • 4
  • 28
  • 46
0

The problem is that you named your EventEmitter as "click" which is the same name that Angular uses for naming the click event. So change the name of your EventEmitter from "click" to "clickEmitter" and this will solve your problem.

<my-button [disabled]="true" (clickEmitter)="onClick()"></my-button>
@Output()
public clickEmitter = new EventEmitter();
gbarzagli
  • 71
  • 5
  • 1
    I don't like this idea. Developer could write `(click)` event handler on `my-button` because he forget to use `clickEmitter` and click will work even if it shouldn't. – Makla Jul 05 '18 at 04:18
0

I recently had this problem and the easiest solution I found was to put a div around the button element and proxy the click calls from there:

@Component({
  selector: "my-button",
  template: `<div (click)="proxyClick($event)">
                 <button
                     type="button"
                     [disabled]="disabled"
                     mat-flat-button
                     [color]="color"
                 >
                     {{text}}
                 </button>
            </div>`
})
export class MyButton
{
    @Input() disabled = false;
    @Input() text = "Click me";

    public proxyClick(event: MouseEvent): void {
        if (this.disabled) {
            event.stopImmediatePropagation();
            event.stopPropagation();
        }
    }
}

I'm using Angular Material, it may be the cause why every solution "proxying" the click directly from the button wasn't working. I also only see this happening in Chrome.

Plinio Mayer
  • 51
  • 1
  • 7