Javascript: get element ID from event - javascript

How to get the ID of an element passed as (e)?
window.addEventListener('load', function(){
var tags = document.getElementsByClassName("tag");
for (i=0; i<tags.length; i++){
tags[i].addEventListener('mousedown', function(e){ tagClick(e) }, false);
}
}, false);
function tagClick(e){
/* here I'm gonna need the event to cancel the bubble and the ID to work with it*/
alert('The id of the element you clicked: ' + [?object].id);
[?object].className='newClass';
e.stopPropagation();
e.cancelBubble = true;
}
I need to get the element/object inside tagClick so I can change its properties
html:
<div class="tag">
<img src="/images/tags/sample.jpg"/>
<label class="tagLabel">Sample</label>
</div>
See, the element with the event attached is the div, but ig gives me the image object instead when using e.srcElement.

When you bind an event listener with addEventListener, it's called with this referring to the element you bound the event on. So this.id will be the id of the element (if it has one).
alert('The id of the element you clicked: ' + this.id);
But you're breaking that with this line:
tags[i].addEventListener('mousedown', function(e){ tagClick(e) }, false);
...because you're putting an extra function in the middle, then calling tagClick without setting this. There's no need for that extra function, change that to:
tags[i].addEventListener('mousedown', tagClick, false);
...so this doesn't get messed up. Or alternately if you prefer to have the extra function, ensure this is maintained using Function#call:
tags[i].addEventListener('mousedown', function(e){ tagClick.call(this, e) }, false);
...but there's no reason to do that with the tagClick function shown.
The (standard) event object also has the properties target (which may not be the element you bound the event on, it may well be a descendant) and currentTarget (which will be the element you bound the event on). But this is convenient and reliable if you use addEventListener (or even attachEvent, on IE).

You can get the target of the event with e.target.
However keep in mind that some browsers consider text nodes to be a target, so try something like this:
var t = e.target;
while(t && !t.id) t = t.parentNode;
if( t) {
alert("You clicked element #"+t.id);
}
This will find the first element that actually has an ID.
Happy New Year!
EDIT: On second thought, if it's the "tag" element itself you want to refer to, just use this. In an event handler, this refers to the element that actually has the handler. Although in this case you'll need to change your handler to ('mousedown', tagClick, false)
Or better still:
document.body.addEventListener("mousedown",function(e) {
var t = e.target;
while(t && t.nodeName != "TAG") { // note, must be uppercase
t = t.parentNode;
}
if( t) {
alert("You clicked on #"+t.id);
}
},false);
Fewer event handlers is always better.

document.getElementById("body").addEventListener("mousedown", function(e){
console.log(e.target.id);
});
enjoy.

Related

javascript - Mouse Click on parent element , but prevent it's child element to fire event

How to define on child element, not to trigger an event,
like on .mouseclick = 'no-event' or : .mousedown = 'no-event'
with natural Javascript command?
So, it's parent will get the the first event before bubbling-up,
the parent element event will get e. target = e.currentTarget
I need to do it on some specific child elements, and some not.
On parent element the 'capture', does not give the correct behaviour
as mentioned above.
All other solutions I follow on the web, are giving many 'tricky' solutions
that don't work correctly.
var parentEl = document.getElementById('parent');
var childEl = document.getElementById('child');
parentEl.addEventListener('click', function(event) {
}, true)
childEl.addEventListener('click', function(event) {
}, true)
If you pass the true on eventListener it stops the event from bubbling.
You could give the children a custom class which determines it should be clickable or not.
Inside the callback function for it's parent container check which class the target is using and act accordingly.
Here's an example:
document.getElementById("container").addEventListener('click', function(e) {
if (e.target.className == "clickable") {
console.log("I should do something!");
} else {
console.log("I should NOT do something!");
}
});
<div id="container">
<div class="clickable">
this is clickable
</div>
<div>
this is not clickable
</div>
</div>

js line causes code above it not to execute

Here's a pen with the full html: https://codepen.io/froggomad/pen/WLdzoB
I'm writing 2 functions - one to show hidden content, and one to hide it. I'm wanting the show() function to execute on the parent div and the hide() function to execute on the div with the selector .click-text.
However, I'm switching text on .click-text from show to hide so I don't want the hide function to remain on the text at all times. I also want it obvious that its interactive text when changing to a hide function, so I make it a link.
That's all well, but when attempting to set the onclick Attr of the parent back to the show() function, nothing in the hide block executes at all.
If I remove the line setting the parent's onclick Attr, the script executes as expected. If I set another element's onclick Attr, the script executes as expected.
However, with that line in there, nothing happens and there's no output in the console to indicate an error. I even set an alert with the type of element and classname to ensure I'm targeting the right element.
Get closest parent of element matching selector:
var getClosest = function (element, selector) {
for ( ; element && element !== document; element = element.parentNode ) {
if ( element.matches(selector) ) return element;
}
return null;
}
Show Hidden Element ul.service-category-menu
function show(elem) {
var menu = elem.querySelector("ul.service-category-menu"),
click = elem.querySelector(".click-text"),
parent = getClosest(elem, '.service-category');
;
if (menu.style.display === "none" || menu.style.display === "") {
menu.style.display = "block";
click.innerHTML = "<a href=\"#\">Click to Hide<\/a>";
click.setAttribute('onclick','hide(this);');
elem.setAttribute('onclick', 'null');
}
}
Hide Element
function hide(elem) {
var parent = getClosest(elem, '.service-category'),
menu = parent.querySelector("ul.service-category-menu"),
click = parent.querySelector(".click-text")
;
alert(parent + "\n" + parent.className);
//Outputs div element with expected class name (class name is unique on each div)
if (menu.style.display === "block") {
menu.style.display = "none";
click.innerHTML = "Click to Show";
click.setAttribute('onclick', 'null');
//the above lines don't execute when the following line is in place. There's no error in console.
parent.setAttribute('onclick','show(this)');
}
}
First off, I must confess that I'm against using onclick attributes. If you're not using a framework such as VueJS or React, I think HTML and JS should remain separated for better control and maintainability.
You can use addEventListener, removeEventListener, and e.stopPropagation() to avoid triggering multiple event handlers.
Events have two phases:
Event capture: the event spreads from the document all the way down to the target element.
To catch an event during this phase, do:
elm.addEventListener('click', myFunc, true);
Event bubbling: the event bounces back from the target to the document.
To catch an event during this phase, do:
elm.addEventListener('click', myFunc, false); /* or just omit the 3rd param */
Using e.stopPropagation() allows you to break that chain.
// When the DOM is ready
window.addEventListener("DOMContentLoaded", init);
function init() {
// Get all categories
var $categories = document.querySelectorAll(".service-category");
// For each of them
Array.from($categories).forEach(function($category) {
// Add an event listener for clicks
$category.addEventListener("click", show);
});
}
function getClosest(element, selector) {
for (; element && element !== document; element = element.parentNode) {
if (element.matches(selector)) return element;
}
return null;
}
function show(e) {
var $menu = this.querySelector("ul.service-category-menu"),
$click = this.querySelector(".click-text");
if (["none", ""].includes($menu.style.display)) {
$menu.style.display = "block";
$click.innerHTML = 'Click to Hide';
$click.addEventListener("click", hide);
// Remove the `show` event listener
this.removeEventListener("click", show);
}
e.stopPropagation();
}
function hide(e) {
var $parent = getClosest(this, ".service-category"),
$menu = $parent.querySelector("ul.service-category-menu"),
$click = $parent.querySelector(".click-text");
if (!["none", ""].includes($menu.style.display)) {
$menu.style.display = "none";
$click.innerHTML = "Click to Show";
$click.removeEventListener("click", hide);
$parent.addEventListener("click", show);
}
e.stopPropagation();
}
.service-category{display:inline-block;border:3px solid #ccc;margin:1%;font-weight:700;font-size:3.5vw;cursor:pointer;background-color:#fff;z-index:3;background-position:center;background-size:cover;color:#000}.click-text{text-align:right;font-size:1.25vw;font-style:italic;font-weight:700;padding-right:1%}.service-category:hover .click-text{color:#b22222}.service-category-menu{display:none;margin-left:8%;margin-right:8%;margin-top:1%;background-color:#fff;font-weight:700;font-size:1.6vw;border-radius:10px}
<div class="service-category web-back" id="web-back">
<div class="row-overlay">
Web <br /> Development
<div class="click-text">Click to Show</div>
<ul class="service-category-menu web">
<li>
Some text...
</li>
</ul>
</div>
</div>
<div class="service-category web-front" id="web-front">
<div class="row-overlay">
Web <br /> Design
<div class="click-text">Click to Show</div>
<ul class="service-category-menu web">
<li>
Some text...
</li>
</ul>
</div>
</div>
It is executed, it's just after you click that Click to Hide, the event continues to parent and the event handler of the parent executed. Thus, what exactly happen is (with that line), after hide() called, you inadvertently called show().
In javascript it's usually called bubbles (when you click the children, the click handler of parent will also be executed after click handler of children complete).
So the solution, you can add this line at the end of the hide() function
event.stopPropagation();
To stop the event from continuing to the parent
Setting event.stopPropagation as mentioned in the other answer will potentially fix your issue. Alternatively, you can change the last line of your hide function to window.setTimeout(e => parent.setAttribute('onclick','show(this)'), 0).
What's happening right now is:
You click
it executes your hide function, and during that function it binds a click event to the parent
The click propagates to the parent and executes the newly bound function, re-showing the content.
By using setTimeout(fn, 0), you're making sure the click event completes before the function is bound to the parent.

Gracefully bubble up with a clicktarget

I am working with this plugin that runs off of the data attribute. Basically when you click anywhere on the body it will determine if the click target has this specific data-vzpop. The problem is lets say I have a div and inside the div is an a href. It only acknowledges the a href as the click target and not the div (which makes sense).
What I want to try and do in some cases is put the data attribute on the containing div that way anything within the div works on click.
Here is a sample of the issue with jsfiddle it requires viewing the console so you can actually see which element is registered as being clicked.
<div data-vzpop>
Click Me
</div>
$('body').on('click', function(evt){
var clickTarget = evt.target;
if ($(clickTarget).attr('data-vzpop') !== undefined){
evt.preventDefault();
console.log('called correctly')
} else {
console.log('not called correctly')
}
console.log(clickTarget)
});
fiddle
You would use Event delegation:
$('body').on('click', '[data-vzpop]', function(evt) {
This will only trigger when the evt.target has a data attribute of data-vzpop, no matter the value.
If you want items inside the [data-vzpop] to trigger it as well, you would use your original click event but check that the $(clickTarget).closest('[data-vzpop]').length > 0 to determine if it's a nested target.
$('body').on('click', function(evt){
var clickTarget = evt.target;
if ($(clickTarget).attr('data-vzpop') != null ||
$(clickTarget).closest('[data-vzpop]').length > 0){
evt.preventDefault();
console.log('called correctly')
} else {
console.log('not called correctly')
}
console.log(clickTarget)
});

How to get the element clicked (for the whole document)?

I would like to get the current element (whatever element that is) in an HTML document that I clicked. I am using:
$(document).click(function () {
alert($(this).text());
});
But very strangely, I get the text of the whole(!) document, not the clicked element.
How to get only the element I clicked on?
Example
<body>
<div class="myclass">test</div>
<p>asdfasfasf</p>
</body>
If I click on the "test" text, I would like to be able to read the attribute with $(this).attr("myclass") in jQuery.
You need to use the event.target which is the element which originally triggered the event. The this in your example code refers to document.
In jQuery, that's...
$(document).click(function(event) {
var text = $(event.target).text();
});
Without jQuery...
document.addEventListener('click', function(e) {
e = e || window.event;
var target = e.target || e.srcElement,
text = target.textContent || target.innerText;
}, false);
Also, ensure if you need to support < IE9 that you use attachEvent() instead of addEventListener().
event.target to get the element
window.onclick = e => {
console.log(e.target); // to get the element
console.log(e.target.tagName); // to get the element tag name alone
}
to get the text from clicked element
window.onclick = e => {
console.log(e.target.innerText);
}
use the following inside the body tag
<body onclick="theFunction(event)">
then use in javascript the following function to get the ID
<script>
function theFunction(e)
{ alert(e.target.id);}
You can find the target element in event.target:
$(document).click(function(event) {
console.log($(event.target).text());
});
References:
http://api.jquery.com/event.target/
Use delegate and event.target. delegate takes advantage of the event bubbling by letting one element listen for, and handle, events on child elements. target is the jQ-normalized property of the event object representing the object from which the event originated.
$(document).delegate('*', 'click', function (event) {
// event.target is the element
// $(event.target).text() gets its text
});
Demo: http://jsfiddle.net/xXTbP/
I know this post is really old but, to get the contents of an element in reference to its ID, this is what I would do:
window.onclick = e => {
console.log(e.target);
console.log(e.target.id, ' -->', e.target.innerHTML);
}
This is the esiest way to get clicked element in javascript.
window.addEventListener('click', (e) => console.log(e.target));
$(document).click(function (e) {
alert($(e.target).text());
});
pass "this" as argument when you call the function:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<span onclick="click_here(this);">clicked</span>
<script>
function click_here(elmnt){
alert($(elmnt).text());
}
</script>
Here's a solution that uses a jQuery selector so you can easily target tags of any class, ID, type etc.
jQuery('div').on('click', function(){
var node = jQuery(this).get(0);
var range = document.createRange();
range.selectNodeContents( node );
window.getSelection().removeAllRanges();
window.getSelection().addRange( range );
});

How can I attach event to a tag which is in string form?

I'm creating html on runtime like this:
var myVar = "<div id='abc'>some clickable text</div>"
Now, I want to attach some event, say onclick, to this div. How can I do that on next line? I'll add this to DOM later.
PS: I've to accomplish this without using JQuery.
Instead of building your div as a string, you'll want to use document.createElement('div'). This way you will have a real dom object, and can get and set it's propeties, including onClick
Will this help? Since you dynamically generate it, you know the control id of the DIV.
document.getElementbyId('abc').onClick = foo;
function foo()
{
alert("All your impl to go here");
}
Try building the div as a DOM element first.
var myVar = document.createElement("div"),
parentDiv = document.getElementById("parent_div");
parentDiv.appendChild(myVar);
myVar.innerHTML = "some clickable text";
if(myVar.addEventListener){
myVar.addEventListener("click", clickFn, false);
}
else if(myVar.attachEvent){
myVar.attachEvent("onclick", clickFn);
}
else{
myVar.onclick = clickFn;
}
The addEventListener method is standard, but not every browser plays nice with the standard.
EDIT: As mentioned, an element must be added to the DOM first.
Or you can use this technique: attach event to the document.body. Then if the event target is not the needed div than just do nothing. It is the same techinque jquery uses for its live function:
// crossbrowser event attachment function
function listen(evnt, elem, func) {
if (elem.addEventListener) {
elem.addEventListener(evnt, func, false);
}
else if (elem.attachEvent) {
var r = elem.attachEvent("on" + evnt, func);
return r;
}
else window.alert('I\'m sorry Dave, I\'m afraid I can\'t do that.');
}
// this is an analog of the jquery.live
var assignLiveEvent = function(id, evnt, callback) {
var handler = function(e) {
e = e || window.event;
e.target = e.target || e.srcElement;
if (e.target.id == id) {
//your code here
callback(e);
}
};
listen(evnt, document.body, handler);
};
var myVar = "<div id='abc'>some clickable text</div>";
assignLiveEvent("abc", "click", function(e) {
//your code here
});
// now you can add your div to DOM even after event handler assignation
Here is demo.
Brian Glaz is totally right but, if for some reason, you really need to do it this way, you have two options:
you can only add events to something that is already in the DOM, using pure javascript, so you would have to include it in the html like:
document.body.innerHTML += myVar;
and then, attach the event with
document.getElementById('abc').addEventListener('click', function(e){
//your code
}, 1);
With jQuery, you could use .live() to attach events to elements that are not yet present in the DOM:
$('#abc').live('click', function(e){
//your code here
});
so you could add the div later...

Categories

Resources