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;
}
Related
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()
}
})
I have a custom directive called HandleScroll and I need to add this directive to all input elements. When I initially built it , it was only needed on one input elements so I added it manually as:
< Input handle-scroll....
But now I realize that I need to add this directive to each and every input element. Is there an easy way to do this using Javascript or will I have to sit and manually add this directive to each input tag ?
Update----Thank you everyone for your help, due to some updates I no longer need to use the directive , but need to bind an event listener to each input field. I've posted the new question at: Adding an event listener to each input field , if you can help please do , I greatly appreciate it !
In your directive class, you can set the selector in your decorator :
#Directive({
selector: 'input'
})
export class HandleScroll...
You can wrap input with angular component. And just use the component everywhere.
<app-input-with-directive></app-input-with-directive>
In AngularJS you can use following.
function MyCtrl($scope, $compile, $window, $document) {
$window.onload = function() {
var inputs = $document[0].querySelectorAll('input');
inputs.forEach(input => {
input.setAttribute('handle-scroll', true);
$compile(input, $scope);
});
};
}
Basically, we are trying to add a new attribute to each input element on the page and recompiling the element.
In my application I have a help section that is only visible when this.car.helpOpen property is true, and initially the property is false:
<ion-item *ngIf="car.helpOpen">
<div class="car-help-content" item-content>
<img src="{{testURL}}" />
<p class="explanations" [innerHTML]="car.helpText"> </p>
</div>
</ion-item>
I have a method that changes the value of this.car.helpOpen to true and after that adds an event handler to all of the <a> elements(car.helpText contains <a> elements) inside the <p> element:
toggleHelp(input){
input.helpOpen=!input.helpOpen;
$("p.explanations").find("a").click(function(e){
alert(e.target.innerHTML);
});
}
But I think that the attachment of event handlers is happening before the *ngIf actually shows the help section, and that's why the event handlers don't get attached. If I remove *ngIf completely and execute the function toggleHelp(), the handlers get attached.
Is there a way I can work around this?
Maybe there is a way to add the event handlers without using jQuery? (without changing the actual innerHTML of the element)
ngIf is a structural directive, it creates/destroys content inside the DOM. you can hide the elemnt by css like add class will make the display:none
What is the difference between *ngIf and [hidden]
You can add a click event to p elemnt and check the target element if it 's a this will look like add event listener to a element with pure javascript without jquery
template
<p [innerHTML]="html" (click)="toggleHelp({},$event)"></p>
toggleHelp function
toggleHelp(input , e:MouseEvent) : void{
input.helpOpen=!input.helpOpen;
console.log('event element',e);
if ((e.target as HTMLElement).tagName === 'A') {
let target = e.target as HTMLElement;
// everything here will run if you click on a element
alert(target.innerHTML)
}
}
stackblitz example
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.
I am trying to implement a function which changes style of element on click and remove it when unfocus. For ex: When element2 is clicked, it should remove class of other elements, and add class to the clicked element only.
<div class="dope" id="element777"></div>
<div class="dope" id="element2"></div>
<div class="dope" id="element11"></div>
<div class="dope" id="element245"></div>
<div class="dope" id="element60"></div>
.....(More are created automatically, numbers are not estimatable)
I couldnt know the element ids that are created. The only remains same is class.
I have tried this, but its an unprofessional approach.
$('#element1').click(function(){
$("#element1").addClass(dope2);
$("#element2").removeClass(dope);
$("#element3").removeClass(dope);
$("#element4").removeClass(dope);
});
$("#element1").blur(function(){
$("#element1").removeClass(dope);
});
$('#element2').click(function(){
$("#element2").addClass(dope2);
$("#element1").removeClass(dope);
$("#element3").removeClass(dope);
$("#element4").removeClass(dope);
});
$("#element2").blur(function(){
$("#element2").removeClass(dope);
});
What is the best approach for automating this function, instead of adding click and blur (unfocus) function to ALL of elements ?
You can listen for click events on any div with an id containing the word "element', then target its siblings elements (those that are not clicked, without referring to them by id). This might do it:
$("div[id*='element']").click(function(){
$(this).addClass('dope').siblings('.dope').removeClass('dope');
});
Your jQuery could be vastly simpler if you leverage this and siblings:
Instead of:
$("#element1").addClass(dope2);
$("#element2").removeClass(dope);
$("#element3").removeClass(dope);
$("#element4").removeClass(dope);
It could be:
$('.dope').click(
function() {
$(this).addClass(dope2).siblings().removeClass(dope);
}
);
NOTE:
Do you have a variable called dope with the class name, or is dope the class name? If it's the classname, you need to put it in quotes: $(this).addClass('dope2'), etc.
If you are removing the class dope, then will want to add a class you can always use to select these elements (so that when you remove dope, it continues to work).
Button part:
$("div").click(function(){
if($(this).hasClass("dope") || $(this).hasClass("dope2")){
$(this).addClass("dope2");
$(".dope").not($(this)).removeClass("dope");
}
})
Blur part:
$("div").blur(function(){
if($(this).hasClass("dope") || $(this).hasClass("dope2")){
$(this).removeClass("dope");
}
}
I would recommend using the :focus css selector rather than using javascript to do what you are doing... Read more here. Instead of having a click listener, the focus selector will take care of that for you and automatically remove the styling when the element is out of focus.