AngularJs ng-click $event passes child element as target - javascript

For each td element in a table I have an attached ng-click. Here is the (simplified) html for each table cell:
<td ng-click="cellClicked($event)">
<span ng-if="!cellEdit">{{event.eventName}}</span>
<input type="text" ng-if="cellEdit" ng-model="event.eventName">
</td>
And my (simplified) ng-click function:
scope.cellClicked = function (event) {
rowScope.cellEdit = true
angular.element(event.target).find('input').focus()
}
Its my goal to:
User clicks a table cell
Cell changes to "edit mode"
Give focus to the input element located inside the td.
Right now this is working as long as the user clicks inside the td element but not on the span element:
console.log(angular.element(event.target)) #--> [td...] (as desired)
However if the user clicks on the span element within the td:
console.log(angular.element(event.target)) #--> [span...]
In this use case assigning focus does not work. I was hoping to access the parent element of the span doing something like:
angular.element(event.target.closest('td'))
or
angular.element(event.target.parentNode)
But it appears when an element gets passed through via $event and accessed there is no parent context.
How can I either:
Prevent clicking the span element firing the td's ng-click
On click of span element pass through it's html parent

Changing:
angular.element(event.target)
to:
angular.element(event.currentTarget)
fixed my issue.
It seems to me using event.currentTarget is preferred to event.target in the majority of usage cases.

event.target.closest('td') won't work because event.target is a DOM element and it doesn't have method closest. You need to create a jQuery object to use this method.
Try to find closest td like this:
angular.element(event.target).closest('td')

In Angular 7.x
myClickHandler($event) {
this.selectedElement = <Element>$event.target.closest('.list-item');
}
html:
<div class="list-item" (click)="myClickHandler($event)">...</div>

Related

When a `label` element contains a child `span`, clicking the label triggers on the child but not the parent

In this example, I've created a label group with a header, and have attempted to attach a click listener to each label; I eventually want an input inside each label, but it is not necessary to illustrate the behavior I don't understand.
I am seeing different behavior depending on whether I wrap the label text in a span tag:
When the label without a child span is clicked, the event handler is called once as I would expect, on the label element.
When the label with a child a span is clicked, the event handler is still called only once, but this time for the child span and not for the parent label.
I would have expected, in the second scenario, the event handler to trigger twice: once for the parent label, and once for the child span. Can someone explain why the addition of this span element seems to be preventing the event handler from propagating to the parent label?
var settingsGroup = document.getElementById("settings");
settingsGroup.querySelectorAll('.setting').forEach(function(setting) {
var options = setting.querySelectorAll('label');
options.forEach(function(option) {
option.addEventListener("click", function(ev) {
console.log(`${this.id} clicked: ${ev.target.tagName}`);
});
});
});
<div id="settings">
<div class="setting" role="group">
<div id="header">
<em>
A setting
</em>
</div>
<label id="option-a">
Option A
</label>
<label id="option-b">
<span>
Option B
</span>
</label>
</div>
</div>
This is normal. e.target is the element that was the target of the event (the span in the case of <label><span>...</span></label>. The target of the event is the span, and then the event propagates (bubbles) to its parent label, where it gets handled by your event handler.
If you want to look at the label instead, either use this as you have for id, or use e.currentTarget (the element the event is currently being delivered to).
This diagram from the old DOM3 Events spec is handy for understanding event flow:
You can use "pointer-events" CSS directive to stop span HTML elements receiving mouse events.
span
{
pointer-events: none;
}

Angular - execute code AFTER *ngIf has shown 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

Retrieve parent element ID on focus out

I'm trying to retrieve the TR element's ID, whenever the user removes focus from that TR. Triggering the event is easy enough, but I can't work out how best to retrieve the ID
$(".row-identifying-class").focusout(function (e) {
var rowID = e.target.id; // Returns the ID of the TD/input/label etc the user last clicked on
alert(e.target);
})
The problem appears to be that although the function above triggers whenever I remove focus from the TR, the event is actually triggered by the child element (eg the TD, input box, button etc), not the parent element.
Is there any way to retrieve the original TR, without having to trace back through the parent of each object until I hit a TR element? Perhaps by passing the ID in directly when creating the function?
You're correct in that e.target will refer to the element that raised the new event which caused the focusout to fire on the tr.
Instead, use the currentTarget property as that will point to the event bound element instead, or more simply just this.id:
$(".row-identifying-class").focusout(function(e) {
console.log(e.currentTarget.id);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr class="row-identifying-class" id="tr">
<td>
<input type="text" value="cause a focusout on me..." />
</td>
</tr>
</table>
Use this or e.currentTarget instead of e.target
$(".row-identifying-class").focusout(function (e) {
var rowID = this.id;
alert(rowID);
});
this within a jQuery event handler will be the element instance of the matching selector the event occured on

Getting String Value Of JavaScript Button

I have a list of buttons that is created by the DOM which references an array. When a button in the list is clicked, I want to retrieve the String that is displayed on the Button.
I have tried the following code to reference the string value, but get undefined:
this.String; inside the function when the button is clicked to retreive the string.
How can I properly retrieve the string.
The click handling function is:
$('.timeButtons').click(function() {
confirmation.push(this.textContent);
})
This is how the list of buttons is created:
var populateList=function(array){
var list = document.createElement('ul');
list.className="delete";
for(var i = 0; i < array.length;- i++) {
var item = document.createElement('li');
var itemButton=document.createElement('button');
itemButton.style.cssText='background:#f85a5a; border:none; width:200px; height:50px; margin-bottom:50px; align:center; border-radius:25px; color:#ffffff;'
itemButton.appendChild(document.createTextNode(array[i]));
item.appendChild(itemButton);
list.appendChild(item);
}
return list;
}
Assuming that this is a reference to the button element in question, you can use this.textContent to get the button's text. (Or .innerHTML.)
Demo: http://jsfiddle.net/w0ntsrLx/
Or since in your edited question you seem to be using jQuery, use the .text() method. In a comment you say that the containing div has the "timeButtons" class, so bind a delegated handler to that div as follows:
$(".timeButtons").on("click", "button", function(e) {
confirmation.push($(this).text());
});
Demo: http://jsfiddle.net/w0ntsrLx/1/
That way the function will only be called if the click is on a button element within the .timeButtons div, and this will be the clicked button. The click handler that you show in your question with $(".timeButtons").click(...) is bound to the div and doesn't in any way test for the buttons, so within the handler this will be the div, not the clicked button.
Check this out
Assuming you want pure javascript code,
Whenever an event is triggered, an object is passed back in callback (generally being named as 'event'). this object has many properties including source element, position of click and many more.
get the element using event.srcElement
You can use element.innerHTML or element.innerText to find out the content of the Button.
There is a difference between using innerText and innerHTML, but in your case, both can be used.
Also, you can use jquery too to easily append child, create elements and binding events.

how to find the class name of 'deepest' div in javascript/jquery?

I am aware that e.target contains the info of the element just below the cursor, but what if I want to know the class name of the div which has a table>tr>td>button in it and I'm clicking that button inside that td. I know this events bubbles up and there should be a way to find out if the div exists in that bubbling levels. Any help.
Scenario: button is inside a modal window. How do I find the modal windows class name on click of the button inside it.
Use .closest() to traverse up the DOM to the nearest match:
var parentDiv = $(yourButton).closest('div');
Or in the button's click:
$(yourButton).click(function() {
var nearestParentDiv = $(this).closest('div');
// And read its class
console.log(nearestParentDiv.attr('class'));
});
The selector .closest() accepts can of course be more specific than this, so if if the modal window <div> has some known class but you need to inspect its other classes, you should use the more specific selector.
Yes as you say the event will bubble up to your div, so just make the div handle the event with .on() , like this:
$('#yourdiv').on('click',':button',function(e) {
alert( $(e.delegateTarget).attr('class') );//alerts the classes of #yourdiv
alert( $(this).attr('id'));//alerts the id of the clicked button (if have one)
});
UPDATE:
Fixed obtaining the reference to the original div where the event was attached. With event.delegateTarget from the Event object . Thanks Cristophe and Kevin B. for spotting the error.
See working demo
You can use .parent() to get the parent div attributes like id: http://jsbin.com/ololad/1/edit
$('button').click(function(){
console.log($(this).parent().attr('id'));
});

Categories

Resources