2
votes

I currently need to be more specific in my functionality for a class toggle that needs to only occur in the children within the element being clicked. I have a class of ".node" and when this is clicked it should toggle a class on it's child ".node-dropdown". I have multiple of these nodes with (click)="showNodeDropdown" and currently all the node dropdowns are being hidden or shown at the same time.

HTML

<div class="node" *ngIf="authService.isInternalUser()" (click)="showNodeDropdown()">
<span class=" fa fa-clock-o node-icon"></span>
<p>Menu Title</p>

Keep in mind there are multiple of these elements using (click)="showNodeDropdown()" throughout my page and this is just one example.

JS

showNodeDropdown() {
    $('.node-dropdown').toggleClass('hidden');
}

I tried changing my JS to be something like $(this).children('.node-dropdown).toggleClass('hidden');

however (this) is currently defined only as "object Object"

Is there a way I can get the element that was clicked and set it to (this) so that I can toggle only on it's children? Thanks in advance for any help.

4
You can change your inline click handler to (click)="showNodeDropdown(this)" and it will be passed in as an argument. Or perform your click event binding in js and 'this' will automatically be the element clicked as normal. - Taplar
Hey @Taplar , I just tried this and the only thing that is being passed is (object Object) still. Not sure this will solve my problem. I updated the code to this: showNodeDropdown(e) { alert(e); $(e).children('.node-dropdown').toggleClass('hidden'); } <div class="node" (mouseenter)="showNodeOverlay()" (mouseleave)="hideNodeOverlay()" (click)="showNodeDropdown(this)"> - Nick_M
don't use jQuery inside of Angular Applications - messerbill
That's weird. I wonder if it's something to do with the angular html generation. - Taplar
@messerbill So, what should I be doing here instead? Just writing angular? If so, could you link me to a post that shows something similar? - Nick_M

4 Answers

1
votes

Here are two Angular ways to get the clicked element:

  1. Pass the event target to the handler:
    <div (click)="showNodeDropdown($event.target)" ... >
  1. Define a template reference variable, and pass it to the handler:

    <div #myDiv (click)="showNodeDropdown(myDiv)" ... >
    

In both cases, the event handler can be written as:

showNodeDropdown(element: HTMLElement) {
    let nodes = element.querySelectorAll(".node-dropdown");
    for (let i = 0; i < nodes.length; i++) {
        nodes[i].classList.toggle("hidden");
    }
}

or, using jQuery:

showNodeDropdown(element: HTMLElement) {
    $(element).children(".node-dropdown").toggleClass("hidden");
}
1
votes

It is recommended not to use jQuery inside of Angular Applications. If you need to select DOM Elements use @ViewChild instead:

https://angular.io/api/core/ViewChild

Here an example:

Controller:

@ViewChildren(TestComponent) test: QueryList<TestComponent>

Template:

<ng-container *ngFor="let player_ of players; let i = index">      
      <test></test>
</ng-container>

to print the <test> Elements just do the following inside the TypeScript Controller:

console.log(this.test)

So, you can access them like any variabled declared in the Controller.

1
votes

You can pass $event object here:

(click)="showNodeDropdown($event)"

and then use

showNodeDropdown(event) {
    $(event.target).toggleClass('hidden');
}

My recomendation is not use jquery, instead create a Directive

import { Directive, HostListener, HostBinding } from '@angular/core';

@Directive({
selector: '[appNodeDropdown]'
})

export class NodeDropdownDirective {

@HostBinding('class.hidden') isOpen = false;

@HostListener('click') toggleOpen(evenData: Event){
    this.isOpen = !this.isOpen;
}
}

and use it like this

<div appNodeDropdown *ngIf="authService.isInternalUser()">

of course remember to register the directive in the "Declarations" array of module of the component.

0
votes

Although I know it is best not to use JQuery in my angular application thanks to @messerbill , I still needed to come up with an answer to handle this issue using JQuery. I was able to set an ID to each div that utilized this (click) and pass the ID through the click like so:

 <div class="node" id="booking-node" (click)="showNodeDropdown('#booking-node')">

showNodeDropdown (id: string) {
        $('.node-dropdown').addClass('hidden');
        $(id).children('.node-dropdown').toggleClass('hidden');
    }

This allowed me to gain the results that I was looking for. Keep in mind this is not the best answer, as not using JQuery at all would be the ideal solution, however I did not have this option so this is the JQuery work around.