Get element that was clicked - javascript

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.

Here are two Angular ways to get the clicked element:
Pass the event target to the handler:
<div (click)="showNodeDropdown($event.target)" ... >
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");
}

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.

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.

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.

Related

Is there any way to add a template reference variable dynamically to the newly created DOM element in the TS?

I have created a DOM element using this.document.createElement('h1') and I want the element to be added to section tag with a template reference variable (myTRF), something like below,
<section>
<h1 #myTRF>This is my heading</h1>
</section>
Is there any way it can be achieved in Angular?
First set some Id to section tag. (h1-section - id for section tag)
var header = document.createElement("H1"); var text = document.createTextNode("This is my heading"); header.appendChild(text); document.getElementById("h1-section").append(header);
You can insert DOM elements into a parent div having template reference variable and access it using #viewchildren : queryList dynamically.
#Component({
selector: 'my-app',
template: `
<div #div>#div is a template variable</div>
`,
})
export class App {
#ViewChildren("div") divs: QueryList<any>
ngAfterViewInit() {
this.divs.forEach(div => console.log(div));
}
}
Reference :
https://angular.io/api/core/ViewChildren
What's the use case. I think you might not even need template variable if you are creating it dynamically. How exactly you are planning to use that variable in rest of the template if it's not even defined at compile.

Angular equivalent of JQuery selectors

I want to invoke a method on click of Any div with a given class. In JQuery it was a trivial one liner. Do we have something similar in Angular?
I know we can use a (click) binding to invoke a method on click. But that would require a separate binding for each instance of the div. I want a generic way to bind every div for the given class - as we used to do with JQuery selectors
In Angular you can create a custom directive, assign it to the required blocks and create a click listener via #HostListener.
For example:
HTML
<div appMyDirective>
div 1
</div>
<div appMyDirective>
div 2
</div>
Directive
#Directive({
selector: '[appMyDirective]'
})
export class MyDirectiveDirective {
constructor() { }
#HostListener('click') onClick() {
console.log('Привет')
}
}
May be it suit you
Angular has absolutely different approach. Instead of querying the DOM, we typically bind the event handlers in the markup.
<button (click)="onSave()">Save</button>
Event binding
Can you please elaborate on what you are trying to achieve,will specify the basic of using click and ngClass in angular see if it helps
In you HTML file
<div class="my_class" (click)="clickDiv()"
[ngClass]="isActive ? 'active' : 'notActive'">
Some content
</div>
In .ts file
isActive : boolean = false ;
clickDiv(){
this.isActive = !this.isActive;
}

How to add custom attribute for element using vue directives?

I have custom attribute my-custom-attribute which contains the id for the element I need to add and remove this attribute depending on the boolean.
I already tried this code and it is working fine, is there any way to make it using vuejs directives?
HTML:
<div my-custom-attribute="my_element">
...
</div>
JS:
const el = document.getElementById("some_id");
if(my_bool) {
el.setAttribute("my-custom-attribute", "#my-element");
} else {
el.removeAttribute("my-custom-attribute")
}
You can register a directive as global using the below example, it provides you three lifecycle hooks for you to control the behavior, read the following and try to implement. Let us know if any problem occurs with your implementation and start a separate thread
https://v2.vuejs.org/v2/guide/custom-directive.html
Vue.directive('my-custom-directive', {
// When the bound element is inserted into the DOM...
inserted: function (el) {
// Focus the element
el.focus()
}
})

Multiple Elements with same custom directive vuejs

Hey there, I have some elements with the same custom directive but different values in my page.
I want to get all elements with that directive to process on them.
When I use this code:
Vue.directive('can', function (value) {
console.log(value)
})
it just gave me the first element with the can directive, not all of them, so how I can get all of the elements with the can directive?!
Update:
my elements are like so:
<button v-can="'register-permission'">Register</button>
<button v-can="'buy-permission'">Buy</button>
<button v-can="'Sell-permission'">Sell</button>
I want to access all buttons with the v-can directive in page! How can it be done?
Following Vuejs documentation on custom directive, I would access all of them like this:
Vue.directive('can', {
bind: function (el, binding, vnode) {
console.log(binding.expression)
}
})

Jquery like DOM selection in Angular5

Let's suppose we have Angular component whose content is provided as follows:
<component-A>
<span class = "parent">
<div class = "toBeSelected"> DemoContent</div>
</span>
<div class = "toBeSelected"> DemoContent2</div>
</component-A>
In jQuery if I need to select element by selector toBeSelected
$('.toBeSelected').click(function(){
var clickedSpanTxt = $(this).html();
console.log(clickedTxt);
});
Is there any library exists which helps in selecting nested DOM elements from the component.
As #ContentChildren of Angular5 only selects direct child of the component by selector i.e. I can only select span with the class parent or only one div with class toBeSelected.
Is there any way to select both div with class toBeSelected.
You can use the DOM APIs. As document is directly available in angular component (.ts file). So you can use
let elSelected = document.querySelectorAll(".toBeSelected");
that will return the array of dom elements.
Use the same callback function on both elements, or make toBeSelected another component with a callback function enclosed in it.
Read this

Categories

Resources