[Fixed] Angular detect Click on any of the Links inside a component

Issue

I have a custom side-nav component.

Which can be used link this:

<button (click)="sideNav.open()">Menu</button>

<side-nav #sideNav>
    <a routerLinkActive="active" routerLink="/">Home</a>
    <a routerLinkActive="active" routerLink="/products">Products</a>
    <a routerLinkActive="active" routerLink="/about">About</a>
    <a routerLinkActive="active" routerLink="/contact">Contact</a>
</side-nav>

Clicking the Menu button opens the side nav with contents inside the side-nav tag.

I want to automatically close the side-nav when a user clicks on any of the links.

Can anyone please guide how to add a click handler for all links(and buttons) in my SideNavComponent that automatically closes the ‘side-nav’

Below is my component:

import { Location } from "@angular/common";
import { Component, Input, Renderer2 } from '@angular/core';

@Component({
  selector: 'side-nav',
  templateUrl: './side-nav.component.html'
})
export class SideNavComponent {

  @Input() isOpen: boolean = false;
  @Input() enabled: boolean = true;
  @Input() extraClasses: string = '';
  
  constructor(private location: Location,
    private renderer: Renderer2) {
  }

  ngOnInit() {
  }

  open() {
    this.isOpen = true;
    window.addEventListener('popstate', this.onHardwareBackButton, { passive: true });
    this.location.go('side-nav');
    this.renderer.addClass(document.body, 'noscroll');
  }

  close(goBack: boolean = false) {
    this.isOpen = false;
    window.removeEventListener('popstate', this.onHardwareBackButton);
    this.renderer.removeClass(document.body, 'noscroll');
    if (goBack) {
      window.history.back();
    }
  }

  onHardwareBackButton = () => {
    this.close();
    window.removeEventListener('popstate', this.onHardwareBackButton);
  };
}

Template

<ng-container *ngIf="enabled">
  <nav id="sidebar-nav" [swipe]="true" (swipeLeft)="close(true)" [ngClass]="{'close':!isOpen,'open':isOpen}" class="{{extraClasses}}">
    <ng-container *ngTemplateOutlet="contentTpl"></ng-container>
  </nav>
  <div id="nav-screen-overlay" (click)="close(true)"></div>
</ng-container>

<ng-container *ngIf="!enabled">
  <ng-container *ngTemplateOutlet="contentTpl"></ng-container>
</ng-container>

<ng-template #contentTpl><ng-content></ng-content></ng-template>

I know I can add (click)="sideNav.close()" on all of the links but I want to do it automatically when user clicks on any of the clickable item e.g. links or buttons.

Solution

You can try this, But I wonder why you can’t simply add click event in the html itself, If repeating is your problem then create an array of links and loop(ngFor) it.

allListeners: (() => void)[] = [];
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}

ngAfterViewInit() {
    const myComponent = this.elementRef.nativeElement as HTMLElement;
    const clickableElements = myComponent.querySelectorAll("a, button");
    clickableElements.forEach(eachElem => {
      const listener = this.renderer.listen(eachElem, "click", () => {
        console.log("Element clicked"); //Close sidenav
      });
      this.allListeners.push(listener);
    });
}

ngOnDestroy() {
    //Remove click listeners
    this.allListeners.forEach(listener => listener())
}

Leave a Reply

(*) Required, Your email will not be published