I can't get any of these event listeners to trigger any functions.
The below is in my chrome extension. The alert is triggered but none of the listeners work. The elements are created dynamically so I'm not sure if that makes a difference.
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('.overlay_show').addEventListener('click', alertit);
document.querySelector('.overlay_hide').addEventListener('click', alertit);
});
element html
`<a class='overlay_hide' ><i>Hide<i/></a>`;
`
Any ideas would be helpful?
The elements are created dynamically so I'm not sure if that makes a difference.
It does. If you add the listener before you add the elements, it won't work. When you do document.querySelector('.overlay_show'), it selects the first element that has the class .overlay_show, and adds a listener upon it. Done.
So, you have 2 solutions:
Add the listener after you add the element
But it means that you have to do that each time you do so
Listen for a click on <body> and use e.target
document.body.addEventListener('click', function (e) {
if (e.target.classList.contains('overlay_show')
|| e.target.classList.contains('overlay_hide')) {
alertit()
}
}
Related
So I came across this weird issue and I don't know if I'm blatantly missing something. Visit this page (or any medium article). Open console and inject the following JS code.
for (const elem of document.querySelectorAll('.progressiveMedia-image.js-progressiveMedia-image')) {
elem.addEventListener('click', function () {
console.log(event.target);
});
}
Now click on the big images, expected behaviour should be (please correct me cause I seem to be wrong) that the target element is printed when you click on it the first time and also the second time. But as it turns out when you click on the image (zoomed) the second time (to zoom out) it doesn't print the target in the console.
I thought that there might be some overlay element and hence I bind the event on body to capture all of the events using the following injected JS.
document.body.addEventListener('click', function () {
console.log(event.target);
}, true);
But even with that I only get one console print of the target.
One theory for delegation using body not working might be following -
The newly created element would not be in the body in its time of creation, it will be moved to its place in the DOM tree later on. And hence delegation is not able to find it when did via body but able to capture it via document.
After a bit more exploring and injecting the following JS (taken from here and I know break point can be added, I did do that earlier but to no end so resorted to this.)
var observer = new MutationObserver(function (mutationsList, observer) {
for (var mutation of mutationsList) {
if (mutation.type == 'childList') {
console.log('A child node has been added or removed.');
}
else if (mutation.type == 'attributes') {
console.log('The ' + mutation.attributeName + ' attribute was modified.');
}
}
});
observer.observe(document, {
attributes: true,
childList: true,
subtree: true
});
I don't see any element being added to the DOM on click (it is being added on load) so that theory might not be correct. So I guess now the real question is why Event Capturing through document is able to find the click event where else not from body. I don't think delegation works on initial DOM structure since it would break the purpose.
Also if it is a duplicate please let me know, since I don't really know what to exactly search for.
probably because there is something in front of the zoomed image that intercepts the click event in capture mode and stops propagation.
I've got success with this
document.addEventListener("click", function(e){ console.log(e.target); }, true);
The image (you are trying to target) is dynamically made. After you already clicked the image once you should be able to target it.
document.querySelectorAll('.progressiveMedia-image.js-progressiveMedia-image')
This queries the DOM for all elements that have both the class progressiveMedia-image and js-progressiveMedia-image. You iterate over the result and bind an event listener to the click event of each element.
When you do click on one of the images, the JavaScript that is already running in the page creates new elements and displays them. These new elements might have the same classes, but did not exist originally when you searched the DOM. As such, they do not have their click event bound.
I'm using the code below on my content_script to get mouse target, however, it doesn't get the 'click' trigger on a dropdown with elements created at runtime.
By that I mean, I can see the target of everything, even the dropdown itself, just the elements created are not triggering the function.
$(window).on('click', function(event){
{
console.log(event.target);
}
good to mention mousemove works fine
document.onmousemove = function(e)
{
console.log(e.target);
}
my dropdown is basically a bunch of 'li' inside a 'ul' element, created from another js, displayed as a dropdown, does anyone have any ideas?
The event binding code must be executed when the element it binds to is already there. You need to use Event Delegation with.on() Same question answered here
example:
$(document).on('.select2-results__options .select2-results__option','selector', function(event){
console.log(event.target);
});
This question already has answers here:
why is jQuery click event firing multiple times
(5 answers)
Closed 6 years ago.
I have a small todo list I made for practice. Here is a Fiddle
, I cant seem to figure out why the click event that toggle the class that adds and removes the line-through in the todo works on some items, but not others. I checked in the console and for some reason the ones that don't work, when clicked, are firing multiple times. If some one could give me some direction as to why this is happening I would greatly appreciate it.
// Toggle line-through todo
$('.todo-container').on('click', function(){
$(this).toggleClass('line-through');
console.log("fired")
})
Like Mike commented, you're adding a new handler to the elements again on every enter keypress, instead use event delegation
To further explain:
When you add an event handler as shown below, jQuery looks through the DOM and adds the handler directly to any elements that have the todo-container class.
$('.todo-container').on('click', function()...
or
$('.todo-container').click(function()...
An important caveat is that this will only add the handler to elements that currently exist on the page.
You saw this results of this when you realized that the handler did not function on newly created (dynamic) elements.
Not quite understanding why it didnt work, you moved the event bindings into the handler for the keyup effectively calling the binding each time a new element is created. This seemed to work at first but in practice is flawed because this again adds the handler directly to any elements that have the todo-container class. including the elements that already have a handler defined from a previous call.
Fix one, Event delegation (Prefered method)
In the below example we move the bindings back outside the keyup handler and use $('#todos').on('click', '.todo-container', to attach the listener to the '#todos' element (which always exists on the page). Then, any time you click inside that element, it checks if the child you clicked had the class "todo-container" and if so, will fire off your code. This is event delegation. This will catch events on any dynamic element that matches the selector
$(document).on('keypress', function(e) {
// Add todo
if (e.which === 13 && $('.input-field').val() != "") {
$('#todos').prepend(todoTemplate);
var todo = $('.todo-container');
$('#todos').children().first().find(todo).html($('.input-field').val());
$('.input-field').val("");
}
})
// Remove todo
$('#todos').on('click', '.todo-container-delete', function() {
$(this).parent().remove();
})
// Toggle line-through todo
$('#todos').on('click', '.todo-container', function() {
$(this).toggleClass('line-through');
console.log("hello")
})
Fix two, more specific targeting with :last
You could actually leave the bindings inside the keyup handler, if you specifically target only the newly added element like this:
$('#todos .todo-container:last').on('click', function(){
or
$('#todos .todo-container:last').click(function(){
Fix three, (not really recommended but possible) .off()
You could also leave the bindings inside the keyup handler, if you use .off() to remove the handlers from the previous elements before adding it to all the elements again like this:
$('.todo-container').off().on('click', function(){
I'd avoid this method though because if you dont specifically target a handler to remove (see documentation for how), you are removing all handlers applied to that element wich could definitely bite you down the road
I have kind of strange problem.
I'm trying to add a couple of events to som DOM elements (all existing, some initially hidden:
$self.on("focus", function () {
$self.next().css("display", "inline-block");
});
$self.on("blur", function () {
$(this).next().hide();
});
$self.parent().find(".icon-ok").on("click", function() {
console.log("icon.ok")
});
You can see the relevant part of the DOM here (self is the span user-name):
Later on, the element eventually because visible and I can click on it. However, the event handler is never called. If I remove the blur event, than the click event works. However, I need both.
What's going on here?
How can I fix it?
Looks like the blur cancels out the click (due to event order) but using mousedown instead of blur may help you get both.
UPDATE: Added code based on comment
$self.parent().find(".icon-ok").on("mousedown", function() {
console.log("icon.ok")
});
Your problem might be the classic delegation problem, where in the element is not available in the DOM when the event is bound.
Delegate the event and see if that solves your problem.
$self.on("click", ".icon-ok", function() {
console.log("icon.ok")
});
User $self if that element is visible or any closest ancestor that you can find which is always present in the DOM.
I wonder how can I get the list of event listeners for some event?
Suppose I add the event listener to window with this code:
window.addEventListener('click',
function() {
console.log(111);
// a lot of code ...
}, false)
But if I am about to see these listeners with window.onclick it returns null.
However when I click on the window this event handler fires. Can I see this list with another ways?
elem.onclick property and elem.addEventListener('click') do not depend on each other, but the order of attaching listeners really matters
<body>
<span> body stuff </span>
<script>
var element = document.body
element.addEventListener('click', function(){ console.log(1) })
element.onclick = function(){ console.log(2) }
element.addEventListener('click', function(){ console.log(3) })
</script>
</body>
do click on body and get '1 2 3'
then set element.onclick = null
do click on body and get '1 3'
2.1. the property onclick (which can be assigned to only one listener that is a function, not an array) is available from the script for each element (like any other property)
2.2. There is definetely no way to see the event listeners added with addEventListener from the script, however browser integrated debugger will show their state on any breakpoint (or in any given moment).
In Chrome 32+:
F12 -> Pick 'Elements' (Tab) -> Choose <body> element -> On the right pick 'EventListeners'
In other browsers you may need an extension (Dragonfly, Firebug etc.)
2.3. Chrome debugger will show all eventListeners (sorted by event name) for current element and its parents up to the document. But I do not know if it is possible to see the window event listeners.
If you use jQuery, there is a way to get from script a bunch of listeners added only by jQuery, though it's a different story.