I'm a JS newbie - still learning. I'm looking for a solution similar to this example
for displaying the source link of an image in an alert using onclick. However, I want to apply it to any image on the page, and there are no ID's on any of the images. Perhaps this is an application of the mysterious 'this'? Can anyone help me? Thanks!
No, this has to do with delegate event listeners, and the way events spread across the DOM.
When you click on an element in the page, a click event is generated. For what it matters to your purposes, this event is fired on the element, and it's caught by the function you define with onclick.
But the event also "bubbles up" to the parent, and it's caught by the onclick function defined there, if any. And then to the parent of the parent, and so on.
What you have to do, now, is to catch the event on the root element, which is the document object itself, or maybe the document.body element if you still want to use onclick (which is deprecated).
The event object is passed to the onclick function and it contains the original element that fired the event:
document.body.onclick = function(e) {
var tgt = e.target || e.srcElement;
if (tgt.tagName === "IMG")
alert(tgt.src);
}
(The e.target || e.srcElement part is because in IE<9 the target property is called srcElement.) That's the way you define a delegate event listener. It's not defined on the <img> elements, as you can see, but on their common ancestor.
But since you can define just one click event listener in the traditional way, I'd strongly recommend to use something more modern like the addEventListener method, which lets you add multiple event listeners on the same element for the same event type:
document.body.addEventListener("click", function(e) {
...
});
In Internet Explorer <9 you'll have to use attachEvent, which is quite similar but not the same. For a cross-browser solution, use a common JS framework like jQuery, or Prototype, or whatever.
If I understand your question this is your solution,
var img = document.getElementsByTagName('img');
for(var i=0;i<img.length;i++){
alert(img[i].src);
}
Related
I'm trying to remove an already existing event listener from an object. I've tried several methods (using jQuery .off(), .unbind(), standard removeEventsListeners()), but as stated in the docs they can only remove previously added ones?
Using the Chrome debugger, I can see and remove the specified event listener,
Also, when trying to list the event listeners via jQuery _data() function, it won't list the event. Have been searching for an answer for a couple of hours now.
Can anyone help? Any workaround?
Edit: I have to keep some, so cloning is not possible.
If the event handler was added with addEventListener, you cannot remove it unless you have a reference to the handler function that was added. I assume that must be the case, because if it were hooked up with jQuery's on (or various shortcuts for it), off would work, and you've said it didn't work.
One way to work around that is to replace the element with a clone. When you clone an element using the DOM's cloneNode, you don't copy its event handlers. So if you start out with element, then you can clone it, use insertBefore to insert the clone, then use removeChild to remove the original:
var newElement = element.cloneNode(true); // true = deep
element.parentNode.insertBefore(newElement, element);
element.parentNode.removeChild(element);
Of course, this is indeed a workaround. The proper thing would be not to set up the handler in the first place, or keep a reference to it if you need to be able to remove it later.
In a comment you've said you can't do that, and asked:
Is there a way to add a new event listener that blocks the already existing one?
Only if you can get there first, otherwise no, you can't.
You can't add a new handler that blocks an existing one (not in a standard way cross-browser), but if you can add yours before the other one is added, you can prevent it being called by using stopImmediatePropagation:
// Your handler
document.getElementById("target").addEventListener("click", function(e) {
console.log("Your handler");
e.stopImmediatePropagation();
e.stopPropagation();
});
// The one that you're trying to prevent
document.getElementById("target").addEventListener("click", function(e) {
console.log("Handler you're trying to prevent");
});
<div id="target">Click me</div>
So for instance, if the other handler is added in the window load event, or a jQuery ready handler, you may be able to get yours in first by putting your code in a script tag immediately after the element in question.
A very easy way of doing this is to append nothing to the parent element with .innerHTML. Just be aware this destroys all event listeners that are descendants of the parent element. Here's an example (click 2 to destroy the event listener attached to 1):
const d1 = document.querySelector('#d1');
d1.addEventListener('click', () => console.log(123));
const d2 = document.querySelector('#d2');
d2.addEventListener('click', () => d1.parentNode.innerHTML += '');
<div><button id="d1">1</button></div>
<div><button id="d2">2</button></div>
If I have 10 items, with the class name keyword:
<div class="keyword"></div>
How can I attach an event, for example click, on this element.
I tried the following, but with no luck: (no alert comes up)
document.getElementsByClassName('.keyword').onclick = function()
{
alert(true);
Search.addKey(this.getElementsByClassName('name')[0].innerHTML);
}
Requirements:
Without the onclick attribute
no jQuery or any other library
Note: the elements are not generated on page load. Their number can be different, each times you click a button for eg.
I need a way to attach to all tags with the class 'keyword' in the 'future'.
You should delegate the event. Try this:
if (document.body.addEventListener)
{
document.body.addEventListener('click',yourHandler,false);
}
else
{
document.body.attachEvent('onclick',yourHandler);//for IE
}
function yourHandler(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
if (target.className.match(/keyword/))
{
//an element with the keyword Class was clicked
}
}
You can read more on event delegation on quirksmode.com. AFAIK, this is the best way of achieving what you're trying to achieve. This is how all the major libs (prototype, jQuery, ...) work behind the scenes
Update:
Here's the fiddle, it contains some more explanation. An interesting reference is this page. It helped me understand the way IE and W3C events differ and, crucialy, it helped me understand the value, and countless benefits of Event Delegation
How do I access what events have been bound to a DOM element using JavaScript and NOT using a library/framework or Firefox add-on? Just pure JavaScript. I incorrectly assumed there would be an events object stored as a property of the element which has the binding.
For example if I had bound say, click, dblclick and mouseover to an element how would I do the following NOT using jQuery. Just JavaScript.
function check(el){
var events = $(el).data('events');
for (i in $(el).data('events')) {
console.log(i) //logs click dblclick and mouseover
}
}
I know jQuery stores an events object as a data property i.e. $(el).data('events') and the eventbug add-on displays the event binding so there must be way.
I will also add that this question came about because I read about memory leaks in older IE browsers and how it's best to remove the bound events before removing a node from the DOM, which lead me to think, how can I test for what events are bound to an element?
You can't reliably know what listeners are on an element if you aren't in complete control of the environment. Some libraries manually control event listeners, e.g. jQuery stores them in an object and adds a custom attribute to the element so that when an even occurs, it uses the custom property to look up the listeners for that element and event and calls them.
Try:
<div id="d0">div 0</div>
<script type="text/javascript">
var el = document.getElementById('d0')
el.addEventListener('click',function(){alert('hey');},false);
// Make sure listener has had time to be set then look at property
window.setTimeout(function(){alert(el.onclick)}, 100); // null
</script>
So to know what listeners have been added, you need to be in complete control.
Edit:
To make it clear, there is no reliable way to inspect an element with javascript and discover what listeners have been added, or even if any have been added at all. You can create an event registration scheme to track listeners added using your event registration methods. But if listeners are added some other way (e.g. directly by addEventListener) then your registration scheme won't know about them.
As pointed out elsewhere, jQuery (and others) can't track listeners that are added directly to elements without using the jQuery event registration methods (click, bind, mouseover, etc.) because they use those methods to register (and call) the listeners.
// list of onevent attributes; you'll have to complete this list
var arr = ['onclick', 'onmouseover', 'onmouseup'];
for ( var i = 0; i < arr.length; i++ ) {
if ( el[arr[i]] != null ) {
// element has an arr[i] handler
}
}
where el is a reference to your DOM element
Complete lists are here
I want to make bookmarklet, and when you press it all the elements on the page gets an onclick event that calls a function with the element as a parameter or at least the elements id/class/something, is that possible? In that case, how would I do it?
click bubbles. So just bind to the <body> and check what the target of the event element is (you'll need to do a bit of event normalization to get around IE being different from everyone else.)
event.target is the actual DOM element, so you can filter on anything that you want to filter on at that point.
This has the advantage that it doesn't matter how many elements are on the page, you only need one event handler for all of them. (Which means performance will be better on pages with hundreds or thousands of elements.)
javascript:void( document.body.onclick = function (event) { event = event || window.event; var element = event.target || event.srcElement; alert(element.textContent) } )
I'm a relative tyro in the Javascript programming arena, so please go easy on me. :-)
I am trying to add an eventListener to various DOM elements on a page. However, some of the elements I'm adding my event to already have an eventListener, and I don't want to supersede that one; I only want to add my event to an element that doesn't already have an event associated with it.
I've looked through a bunch of stuff relating to addEventListener, event.StopPropagation, event bubbling, and so forth, but haven't figured out any way to accomplish this yet.
Is there a way to detect other event listeners on a given element, or some other way to get where I want?
You can check if the on[event] property of that given element is set by using:
if (typeof(document.getElementById("element-id").onclick) == "undefined") {
// event undefined
}
if (typeof(document.getElementById("element-id").onclick) == "function") {
// event defined
}
Notice that this won't work if a javascript library such as jQuery were used to define the event (e.g. by using $("#element-id").click()). I'd recommend you to use jQuery, you can handle events easily with it.
edit: uh, well, afaik it doesn't work if you're using addEventHandler too. It only works if you set your event by using yourElement.onclick = anyFunction