Here's my situation:
I have a custom menu on right mouse click for my project. Here, I have document.addEventListener on click, that makes this menu invisible, like this:
var i = document.getElementById("menu").style;
document.addEventListener('click', function(e) {
i.opacity = "0";
setTimeout(function() {
i.visibility = "hidden";
}, 100);
}, false);
And it's great, works well, but I'm implementing a dropdown submenu that should be opened when you click on a certain element, like so:
$('#change_color').click(function(){
if($('#back_color').hasClass('back_color')){
$('#back_color').removeClass('back_color')
}else{
$('#back_color').addClass('back_color')
}
})
The thing is that when I click on that #change_color then addEventListener is firing, which is obvious.
The question is – how can I prevent that listener function to execute when I click on #change_color?
You can prevent further propagation of the current event in the capturing and bubbling phases using event.stopPropagation() and for simplicity in your code use jQuery.toggleClass().
Code example:
$('#change_color').click(function (e) {
$('#back_color').toggleClass('back_color');
e.preventDefault();
e.stopPropagation();
});
Related
I have a menu that needs to obey the following behavior:
Open with an external button press
Close when there is a click outside it's boundaries
The problem is, that the button to open is also outside the boundaries of the menu and so currently, the button press is opening the editor menu, and then the click listener is immediately closing it again. I've tried using variables and element data so that the click listener only activates if the menu is already open, but the event listener is slower than the button click and so the menu has already been expanded (as far as the listener knows) by the time it is activated. I know I can solve this using timeout so the data isn't changed to "expanded = true" until after the click listener has activated, but this seems kind of clunky and I'm wondering if there is a better option.
Here is a code snippet to demonstrate the problem.
And the js code that accompanies it:
document.addEventListener("click", (event) => {
if (!document.getElementById("menu").contains(event.target) && document.getElementById("menu").dataset.open) {
closeMenu();
}
});
//Expand menu
function openMenu() {
document.getElementById("menu").dataset.open = true;
document.getElementById("menu").style.height = "80vh";
console.log("open");
}
//Collapse menu
function closeMenu() {
document.getElementById("menu").dataset.open = false;
document.getElementById("menu").style.height = "0";
console.log("close");
}
Thanks for your help!
You can have the button prevent its parent element from registering the click by taking the event parameter in openMenu, and calling the stopPropogation method on it.
function openMenu(e) {
e.stopPropogation()
document.getElementById("menu").dataset.open = true;
document.getElementById("menu").style.height = "80vh";
console.log("open");
}
How do I prevent a parent's onclick event from firing when a child anchor is clicked?
Thanks for the answers! Here's my solution based on #Addison Schmidt's answer that fixes a couple of errors:
function openMenu(e) {
if (!event) var e = window.event
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
document.getElementById("menu").dataset.open = true;
document.getElementById("menu").style.height = "80vh";
console.log("open");
}
Source: Event.stopPropagation Not Working
On a click function I have the option of playing audio.
The click is only fired once (after I added .off(), which I seem to have to do for every click event because I think there's something I fundamentally don't get about how javascript works) but the function added to the "ended" listener shows it is firing the number of times the button has been clicked. I presume .play() is also being fired multiple times.
These need to be inside the click event to get the id so how do I stop these kinds of things from happening, here and elsewhere when using js? Adding event.stopPropagation(), event.bubbles = false and .off() everywhere seems unnecessary (and in this case doesn't make a difference anyway).
$('.button').off().on('click', function(event){
event.stopPropagation();
event.bubbles = false;
var id = $(this).attr('id')
if ($(this).hasClass('hasAudio')) {
document.getElementById('audio_'+id).play();
document.getElementById('audio_'+id).addEventListener("ended", function(){
console.log("ended");
});
}
});
Move the ended event outside the click event,you are registering the event each time you click on the button
$('.button').on('click', function(event){
var id = $(this).attr('id')
if ($(this).hasClass('hasAudio')) {
document.getElementById('audio_'+id).play();
}
});
$('[id^="audio_"]').on("ended", function(){
console.log("ended");
});
Each time you click on the button a new event listener will be added to the ended event. To prevent that you can try defining the callback function before hand. That will prevent your event listener to be added in the event loop over and over.
An anonymous function has no signature, hence when you define the event with it, it will think that this is supposed to be a new event listener and invokes it multiple times. Check the working snippets to see the difference. Type something in the input box to see what is happening.
If this is confusing then removeEventListener can be the next option.
function ended(event){
console.log("ended");
}
$('.button').off().on('click', function(event){
event.stopPropagation();
event.bubbles = false;
var id = $(this).attr('id')
if ($(this).hasClass('hasAudio')) {
document.getElementById('audio_'+id).play();
document.getElementById('audio_'+id).addEventListener("ended", ended);
}
});
var input = document.getElementById('some');
function callback(event) {
console.log("PRINT");
}
input.addEventListener("keyup", callback)
// input.removeEventListener("keyup", callback)
input.addEventListener("keyup", callback)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="some" value="" >
Anonymous function as callback
var input = document.getElementById('some');
input.addEventListener("keyup", function(event) {
console.log("PRINT");
})
// input.removeEventListener("keyup", callback)
input.addEventListener("keyup", function(event) {
console.log("PRINT");
})
<input id="some" value="">
This fails because, every time you click the function, you add a new event listener to the button.
document.getElementById('audio_'+id).addEventListener("ended", function(){
console.log("ended");
This is repeatedly adding the event listener to the button.If you need this inside the click event, check to see whether it exists already. If it does, don't add it again.
Use global flag which defines if you want to pause or play. and also use preventDefault (in case of any inline click event used).
You have to remove the registered event listener after your task is completed.
document.getElementById('audio_'+id).removeEventListener("ended", function(){
console.log("ended");
});
Or what you can do is that move the logic for registering event listener outside the click event listener. Like this the event will be registered only once.
document.getElementById('audio_'+id).addEventListener("ended", function(){
console.log("ended");
});
}
$('.button').off().on('click', function(event){
event.stopPropagation();
event.bubbles = false;
var id = $(this).attr('id')
if ($(this).hasClass('hasAudio')) {
document.getElementById('audio_'+id).play();
});
Can someone explain me, how to improve my code, so that it will:
Not call beforeunload event if I'll click on button with class
.btn?
And, if it's possible, without tracking each click event.
I mean:
$(document).on("click", ....);
Here's my current code. It's working, but it prevents page reloading on each action (close, back, click on any button etc)
var reload = $(document).find("[data-prevent-reload]");
if(reload.data('prevent-reload')) {
window.addEventListener('beforeunload', function (ev) {
return ev.returnValue = 'STOP!';
});
}
There is no event that tells you what triggered it so you are stuck with listening to the click events. It is normally done with boolean and check it before calling it.
var ignoreUnload
$(document).on("click", ".btn", function () {
ignoreUnload = true
});
window.addEventListener('beforeunload', function (ev) {
if(!ignoreUnload) return ev.returnValue = 'STOP!';
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a class="btn" href="https://example.com">btn</a>
<a class="" href="https://example.com">not</a>
other option could be to unbind the event instead of the boolean.
I am trying to make it so that when a user clicks down, this happens.
In order,
Does something. (Not being specific, this isn't the important part.)
Mouse up is triggered.
Using: angular, html, css.
Not using: jQuery
Any suggestions?
Thanks!
You attach two event listeners, one while the user has the mouse pressed down mousedown. Once the user lets go the mouseup event is triggered. All mouse event listeners are passed an event object you can use to get information about the event ie: mouse x, and y positions.one of the methods available is event.preventDefault() this will stop the browser doing what it usually wants to do. Example: cmd/ctrl + s will cause the browser to save the html page. preventDefault will stop this.
document.addEventListener('mousedown' function (event) {
// Do something
})
document.addEventListener('mouseup', function (event) {
event.preventDefault()
})
To address OP comment:
var noMouseUp = true
document.addEventListener('mousedown', function () {
if (noMouseUp) {
// do something
noMouseUp = false
}
})
document.addEventListener('mouseup', function (event) {
if (!noMouseUp) {
noMouseUp = true
}
})
Use events.preventDefault(); in the mouseup callback.
Use, right after, event.stopPropagation(); to avoid the event passing to other layered elements.
bypassed_element.onclick = function(event){
event.preventDefault();
event.stopPropagation();
};
I want to detect whenever someone clicks in a div (essentially I want to know when a user is interacting with a section of text on my site, be that by selecting some text or clicking on a link), but I don't want to interfere with what the user is doing.
If I put a onmousedown or onclick event on the div it ends up breaking selection, links, etc. Is there any way to catch these events without causing any interference ?
Onmousedown or onclick shouldn't interfere with anything as long as it doesn't return false;.
You can do this:
document.getElementById("spy-on-me").onmousedown = function () {
console.log("User moused down");
return true; // Not needed, as long as you don't return false
};
If you have other scripts that are attaching behaviour via this method on the page, then to prevent overriding them you can do:
var spyElement = document.getElementById("spy-on-me");
var oldMousedown = spyElement.onmousedown;
spyElement.onmousedown = function () {
console.log("User moused down");
if(oldMousedown) oldMousedown();
};
Yes, I suspect you are currently returning false at the end of the event binding, just don't do that or any of the things in this binding:
$('a').click(function(e) {
e.stopPropagation();
e.preventDefault();
return false;
});
If you do not do any of these three things, jQuery will not stop the event from bubbling up to the browser.
Edit: Sorry didn't realise it was a plain JavaScript question.
you can use do it by adding a event listener as well
var myNode= document.querySelector('.imagegrid');
myNode.addEventListener("click",function(e){
alert(e.target+" clicked");
});
A similar example is demonstrated here
Can't you simply add a click event to the div?
<div id="secretDiv" (click)="secretDivClick()">
then on your component:
secretDivClick() {
console.log('clicked');
}