How to stop event propagation using directive?

Issue

I have a directive that works in other only angular application, but in Ionic with angular it doesn’t.

The directive check if a user is logged, if not, open a popup with some instructions.

When a user is not logged in I have the popup and works, but the event is fired the same despite the preventDefault/stopPropagation etc.

This is the code:

View.component.html

<ion-icon name="pricetag-outline" onlyLogged authorized="true" (click)="saveNews(news)" ></ion-icon>

only-logged.directive.ts

import { Directive, ElementRef, OnInit, HostListener, Input } from '@angular/core';
import { PopoverController } from '@ionic/angular';
import { AuthService } from '../services/auth.service';
import { OnlyLoggedComponent } from '../components/only-logged/only-logged.component';
@Directive({
    selector: '[onlyLogged]'
})
export class OnlyLoggedDirective implements OnInit {

    @Input() authorized = false;
    isUserLogged: boolean;

    constructor(private auth: AuthService, public popoverController: PopoverController) { }

    @HostListener('click', ['$event'])
    clickEvent(event) {

         if (!this.isUserLogged) {
            console.log(event);
            event.preventDefault();
            event.stopPropagation();
            event.stopImmediatePropagation();
            event.returnValue = false;

            event.buttonDisabled = true;

            this.openLogin(event);

            return false;
        }
    }



    ngOnInit() {
        this.auth.isAuthenticated.subscribe((authenticated) => {
            this.isUserLogged = authenticated;
        });
    }


    async openLogin(ev: any) {
        const popover = await this.popoverController.create({
            component: OnlyLoggedComponent,
            event: ev,
            translucent: true,
            animated: true,
            size: 'auto'
        });
        await popover.present();

        const { role } = await popover.onDidDismiss();
        console.log('onDidDismiss resolved with role', role);
    }

}

Ionic Version: 6.18.1
Angular: 13.0.3
Node: 16.13.2

I made a lot of search but I didn’t reach a solution… Someone can tell me what I did wrong?

Solution

From your question I understood that you are trying to intercept a click event using @HostListener directive.

I actually couldn’t get this requested behaviour to work using the hostlistener either.

It seems to me the problem is that stopPropagation in bubbling mode prevents event firing from child to parent.

But the thing is that you are trying to prevent click on the element itself depending on some condition.

In other words you need exactly the opposite, you need to apply stopPropagation in capturing mode, from parent to child

My proposal is to use rxjs fromEventhttps://rxjs.dev/api/index/function/fromEvent

import { Directive, ElementRef, HostListener, Input } from '@angular/core';
import { fromEvent, Subscription } from 'rxjs';

@Directive({
    selector: '[onlyLogged]'
})
export class OnlyLoggedDirective {
    sub = new Subscription();
    logged: boolean = true;

    constructor(private elRef: ElementRef) {}

    ngOnInit() {
        const el = this.elRef.nativeElement;
        this.sub = fromEvent(el.parentNode, 'click', { capture: true})
        .subscribe( (ev: any) => {
            if(ev.target == el) { this.checkLogin(ev); }
        })
    }

    checkLogin(ev: any) {
        if(!this.logged) {
            console.log("user is not logged in", );
            ev.stopImmediatePropagation();
            this.openLogin(ev);
        } else {
            console.log("user is logged in"); 
        }
    }

    openLogin(ev: any) {
        console.log('onDidDismiss resolved with role');
    }
}



<ion-content [fullscreen]="true">
  <div onlyLogged (click)="run()">click on me</div>
</ion-content>

 run() {
    console.log("This click has to be prevented, when user is not logged     in");
 } 

Answered By – tony

Answer Checked By – Pedro (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.