329

What is the easiest way to stop mouse events propagation in Angular ?

Should I pass special $event object and call stopPropagation() myself or there is some other way.

For example in Meteor, I can simply return false from event handler.

HDJEMAI
  • 8,842
  • 44
  • 66
  • 88
Roman Kolesnikov
  • 10,967
  • 11
  • 40
  • 63

15 Answers15

323

If you want to be able to add this to any elements without having to copy/paste the same code over and over again, you can make a directive to do this. It is as simple as below:

import {Directive, HostListener} from "@angular/core";
    
@Directive({
    selector: "[click-stop-propagation]"
})
export class ClickStopPropagation
{
    @HostListener("click", ["$event"])
    public onClick(event: any): void
    {
        event.stopPropagation();
    }
}

Then just add it to the element you want it on:

<div click-stop-propagation>Stop Propagation</div>
HDJEMAI
  • 8,842
  • 44
  • 66
  • 88
dnc253
  • 39,177
  • 38
  • 137
  • 153
289

The simplest is to call stop propagation on an event handler. $event works the same in Angular 2, and contains the ongoing event (by it a mouse click, mouse event, etc.):

(click)="onEvent($event)"

on the event handler, we can there stop the propagation:

onEvent(event) {
   event.stopPropagation();
}
Angular University
  • 40,615
  • 15
  • 71
  • 79
183

Calling stopPropagation on the event prevents propagation: 

(event)="doSomething($event); $event.stopPropagation()"

For preventDefault just return false

(event)="doSomething($event); false"

Event binding allows to execute multiple statements and expressions to be executed sequentially (separated by ; like in *.ts files.
The result of last expression will cause preventDefault to be called if falsy. So be cautious what the expression returns (even when there is only one)

Günter Zöchbauer
  • 558,509
  • 191
  • 1,911
  • 1,506
47

Adding to the answer from @AndroidUniversity. In a single line you can write it like so:

<component (click)="$event.stopPropagation()"></component>
dinigo
  • 5,862
  • 3
  • 33
  • 43
16

This worked for me:

mycomponent.component.ts:

action(event): void {
  event.stopPropagation();
}

mycomponent.component.html:

<button mat-icon-button (click)="action($event);false">Click me !<button/>
Victor Zamanian
  • 2,971
  • 23
  • 30
Brahim JDIDOU
  • 163
  • 1
  • 5
10

If you're in a method bound to an event, simply return false:

@Component({
  (...)
  template: `
    <a href="/test.html" (click)="doSomething()">Test</a>
  `
})
export class MyComp {
  doSomething() {
    (...)
    return false;
  }
}
Thierry Templier
  • 191,422
  • 38
  • 386
  • 349
  • 1
    It __does__ work for click events. At least in the latest version of Angular2. – Jon Oct 25 '16 at 02:26
  • 6
    Returning `false` calls `preventDefault` not `stopPropagation`. – Günter Zöchbauer Jan 04 '17 at 17:07
  • Calling return false does stop propagation in the DOM. Check your facts @GünterZöchbauer It's mentioned in the ng-book. – moeabdol Sep 05 '17 at 12:24
  • 4
    @moeabdol a link could at least demonstrate what you claim, but actually `preventDefault` is called. https://github.com/angular/angular/blob/450a13dea03b5b3cd3b92c5a840a6536ec003f83/packages/core/src/metadata/directives.ts#L215, https://github.com/angular/angular/blob/6279e50d78554781111053e41cafcc8ca50ecc97/packages/core/test/view/element_spec.ts#L264 – Günter Zöchbauer Sep 05 '17 at 12:31
  • 1
    Correct! @GünterZöchbauer Thank you for clarifying this. I wish I could share a link. I followed Nate Murray's advice in his book "ng-book The Complete Book on Angular 4" of returning false; at the end of a function to stop event propagation in the DOM. He describes it exactly the way you mentioned. Sorry for the misunderstanding. – moeabdol Sep 05 '17 at 17:58
10

I had to stopPropagation and preventDefault in order to prevent a button expanding an accordion item that it sat above.

So...

@Component({
  template: `
    <button (click)="doSomething($event); false">Test</button>
  `
})
export class MyComponent {
  doSomething(e) {
    e.stopPropagation();
    // do other stuff...
  }
}
Simon_Weaver
  • 130,769
  • 75
  • 612
  • 659
BrandonReid
  • 1,164
  • 1
  • 12
  • 17
4

I just checked in an Angular 6 application, the event.stopPropagation() works on an event handler without even passing $event

(click)="doSomething()"  // does not require to pass $event


doSomething(){
   // write any code here

   event.stopPropagation();
}
Dipendu Paul
  • 2,453
  • 1
  • 19
  • 16
  • 2
    This is because you're accessing `window.event`. Technically this is deprecated https://developer.mozilla.org/en-US/docs/Web/API/Window/event. It should work, but could in future trip you up. – Simon_Weaver Jun 18 '21 at 17:59
3

Nothing worked for IE (Internet Explorer). My testers were able to break my modal by clicking off the popup window on buttons behind it. So, I listened for a click on my modal screen div and forced refocus on a popup button.

<div class="modal-backscreen" (click)="modalOutsideClick($event)">
</div>


modalOutsideClick(event: any) {
   event.preventDefault()
   // handle IE click-through modal bug
   event.stopPropagation()
   setTimeout(() => {
      this.renderer.invokeElementMethod(this.myModal.nativeElement, 'focus')
   }, 100)
} 
PatrickW
  • 329
  • 3
  • 4
3

I used

<... (click)="..;..; ..someOtherFunctions(mybesomevalue); $event.stopPropagation();" ...>...

in short just seperate other things/function calls with ';' and add $event.stopPropagation()

Ray Dragon
  • 84
  • 1
  • 3
1

Disable href link with JavaScript

<a href="#" onclick="return yes_js_login();">link</a>

yes_js_login = function() {
     // Your code here
     return false;
}

How it should also work in TypeScript with Angular (My Version: 4.1.2)

Template
<a class="list-group-item list-group-item-action" (click)="employeesService.selectEmployeeFromList($event); false" [routerLinkActive]="['active']" [routerLink]="['/employees', 1]">
    RouterLink
</a>
TypeScript
public selectEmployeeFromList(e) {

    e.stopPropagation();
    e.preventDefault();

    console.log("This onClick method should prevent routerLink from executing.");

    return false;
}

But it does not disable the executing of routerLink!

Javan R.
  • 1,821
  • 1
  • 17
  • 16
1

This solved my problem, from preventign that an event gets fired by a children:

doSmth(){
  // what ever
}
        <div (click)="doSmth()">
            <div (click)="$event.stopPropagation()">
                <my-component></my-component>
            </div>
        </div>
JulianRot
  • 11
  • 2
1

Try this directive

@Directive({
    selector: '[stopPropagation]'
})
export class StopPropagationDirective implements OnInit, OnDestroy {
    @Input()
    private stopPropagation: string | string[];

    get element(): HTMLElement {
        return this.elementRef.nativeElement;
    }

    get events(): string[] {
        if (typeof this.stopPropagation === 'string') {
            return [this.stopPropagation];
        }
        return this.stopPropagation;
    }

    constructor(
        private elementRef: ElementRef
    ) { }

    onEvent = (event: Event) => {
        event.stopPropagation();
    }

    ngOnInit() {
        for (const event of this.events) {
            this.element.addEventListener(event, this.onEvent);
        }
    }

    ngOnDestroy() {
        for (const event of this.events) {
            this.element.removeEventListener(event, this.onEvent);
        }
    }
}

Usage

<input 
    type="text" 
    stopPropagation="input" />

<input 
    type="text" 
    [stopPropagation]="['input', 'click']" />
j3ff
  • 5,139
  • 7
  • 39
  • 50
David Alsh
  • 5,303
  • 5
  • 30
  • 45
0

Adding false after function will stop event propagation

<a (click)="foo(); false">click with stop propagation</a>
Fabian Rios
  • 151
  • 1
  • 7
-1

Most of the solutions provided are for versions above Angular 11, For Angular 11 or Below, I found a workaround that can be used:

export class UiButtonComponent implements OnInit, OnDestroy {

  @Input() disabled = false;

  clickEmitter: Subject<any> = new Subject();

  constructor(private elementRef: ElementRef) { }

  ngOnInit(): void {
    this.elementRef.nativeElement.eventListeners()
      .map(listener => this.clickEmitter.pipe(filter(event => Boolean(event))).subscribe(event => listener(event)));
    this.elementRef.nativeElement.removeAllListeners();
    this.elementRef.nativeElement.addEventListener('click', (event) => {
      if (!this.disabled) {
        this.clickEmitter.next(event);
      }
    });
  }

  ngOnDestroy(): void {
    this.clickEmitter.complete();
  }
}

I basically take every listener to the current component and put it on an Observable, then, I register only one listener and manage there the actions.

The example above is an example of disabling the click event on a button given a boolean variable.

  • Looks like you are solving different problem. There are many answers that works for Angular2+. Also you touching nativeElement. You should avoid doing this in any angular version. – Roman Kolesnikov Aug 09 '21 at 13:30