Search code examples
javascriptangularevent-handlingmouseclick-eventangular9

Getting The Source Element From Click Event Handler In Angular


I am still new to Angular and I'm struggling to get the DOM Element of an Angular Click Listener. What I have is the following component HTML:

<div *ngFor="let menuItem of menu; index as itemId" class="menuItem">

    <div class="menuItem__top" (click)="itemClicked($event, !!menuItem.submenu)">
        <!-- Additional divs inside... -->
    </div>

</div>

I would like to toggle a class of "menuItem__top" when it is clicked. My approach was to use a click event listener but I can't get the source Element to apply the class on.

itemClicked(event, hasSubmenu){
    console.log(this) //is the component
    let target = event.target || event.srcElement || event.currentTarget;
    if(hasSubmenu){
      console.log(target);
    }
}

It could be done by getting the target of the $event but this way I would need to check the target and move with closest(".menuItem__top") up to the correct source element. Is there an easy way in Angular to pass the source element of the click listener to the click function or a way to get it inside the click function?

In vanilla JS it would be as easy as using "this" inside the click function, but in Angular this is bind to the component. (In this case, it would be ok to loose the binding to the component if this is the only way.)

I thought about two ways:

  1. Assigning a dynamic reference containing some string and the itemId, passing the itemId and retrieving the reference object based on the itemId in the listener.

  2. Using a @HostListener to listen on every "menuItem__top" click and toggling the class every time.

What do you think is the best way? I feel like I am missing something simple here.


Solution

  • Go the other way around. People are used to jQuery and the way it works (selecting elements already present in the DOM, then adding them a class). So in Angular, they try to do the same thing and grab the element that was clicked, to apply it a class. Angular (and React and others) work the other way around. They construct the DOM from data. If you want to modify an element, start with modifying the data it was generated from.

    This <div class="menuItem__top"> that you click on is constructed from let menuItem. All you have to do is add a property, say "isClicked" to menuItem.

    <div *ngFor="let menuItem of menu; index as itemId" class="menuItem">
    
        <div class="menuItem__top"
            [class.isClicked]="menuItem.isClicked"
            (click)="menuItem.isClicked = true">
                <!-- Additional divs inside... -->
        </div>
    </div>