I have a submit button wrapped in a div. I want to trigger a click event on the submit button when the div is clicked. The problem is, this click event bubbles up and causes a stack overflow/infinite loop. When I try to stop propagation of the child click event, the issue is not resolved.
HTML:
<div class="container">
<input type="submit" value="OK">
</div>
jQuery:
$('.container').click(function () {
var input = $(this).find('input');
input.trigger('click');
input.click(function(event) {
event.stopPropagation();
});
});
This still causes the stack overflow error. So does returning false:
$('.container').click(function () {
var input = $(this).find('input');
input.trigger('click');
return false;
});
Help appreciated!
Don't bind button click event inside container click one. It should be this way
$('.container').click(function() {
var input = $(this).find('input');
input.trigger('click');
});
$('input').click(function(e) {
e.stopPropagation();
alert('button clicked');
});
The problem with your code is that container click triggers inner button click before its respective click handler is even registered, so it have no chance to stop event bubbling.
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
I'm working on my college's project and it's kind of like a web-text-based game. So I'm interested in a click event on a document to change the context and I did it with the code below.
The problem is that it keeps repeating everything and wont allow typing in the input.
const homepage = document.querySelector('#homepage')
document.addEventListener('click', function() {
/*I console.log to check that the function is still repeating*/
console.log('check')
homepage.innerHTML = `<div> hello what's your name? </div>`
document.addEventListener('click', function() {
homepage.innerHTML = `<div> my name is <br>
<input id="name"> </input> <br>
<button> submit </button<
`
})
})
#homepage {
text-align: center;
}
<div id="homepage"> click to change the content </div>
I will try to explain what is the exact issue that is happening below.
Here is your code
const homepage = document.querySelector('#homepage')
// You are adding a click event listner to your DOM
// This will trigger when ever you click on your html page
document.addEventListener('click', function () { // Code Section 1
console.log('this is a console log from first click event listner');
homepage.innerHTML = `<div> hello what's your name? </div>`;
// You are adding an another click event listner to your DOM
document.addEventListener('click', function () { // Code Section 2
console.log('this is a console log from second click event listner');
homepage.innerHTML = `<div> my name is <br>
<input id="name"> </input> <br>
<button> submit </button<
`;
})
})
#homepage {
text-align: center;
}
<div id="homepage"> click to change the content </div>
You have added a click event listner to your document using
document.addEventListener('click', function () {
(Refer Code Section 1 from the comment added in above code).
What this will do?
This will execute the entire set of code which is written inside that block when ever you click any where on your html page.
What is happening inside that code block?
Inside that code block, you are adding an another click event to the document using
document.addEventListener('click', function () {
(Refer Code Section 2 from the comment added in above code).
What happened till now?
You are now adding a click event listner, when ever the user clicks on the html application.
So what does this means?
This simply means that your code will keep on adding new click event listners whenever the user clicks on the application. So if the user click one time on the app, there will be two click event listner. If the user click the third time, one more event listner will be added, so that the total event listner will be three. This will keep on incrementing. This is happening because, you are keep on adding new click event listner when the pervious event listners exist.
So What wrong did happen? How to stop preventing the accumulation of event listners?
You have to revove the event listners before adding new event listners. You can make use of EventTarget.removeEventListener() for this purpose.
Implemetation using EventTarget.removeEventListener()
const homepage = document.querySelector('#homepage');
function listnerFunction() {
console.log('first click event triggered');
homepage.innerHTML = `<div> hello what's your name? </div>`;
// Removing the first event listner
document.removeEventListener('click', listnerFunction);
// Adding second event listner
document.addEventListener('click', secondListnerFunction);
}
function secondListnerFunction() {
console.log('second click event triggered');
homepage.innerHTML = `<div>
my name is <br>
<input id="name"> </input> <br>
<button> submit </button>
</div>
`;
// Removing the second event listner
document.removeEventListener('click', secondListnerFunction);
}
// You are registering click event to your complete html
document.addEventListener('click', listnerFunction);
#homepage {
text-align: center;
}
<div id="homepage"> click to change the content </div>
Explantion
Here I have added a click event listner function to the document using
document.addEventListener('click', listnerFunction);
What this will do?
This will trigger the function listnerFunction when the user clicks on the document.
Handling the second click from the first click event listner
Inside the first click event listner listnerFunction I have updated the innerHTML of your selected element. After this I have removed the first click event listner with
document.removeEventListener('click', listnerFunction);
There after I registered second click event listner with
document.addEventListener('click', secondListnerFunction);
What happens inside second click event listner?
Inside the second click event listner, I updated the innerHTML of your required target and I have removed the click event listner using
document.removeEventListener('click', secondListnerFunction);
This removing of the click event listner is required, after this whenever the user clicks the document, no events will be triggered and hence the user can use the app seamlessly.
const texts = [
"How are you?",
"Tired of studying?",
"Too long enough"
];
let textTake = 0;
document.addEventListener('click', ()=>{
if(textTake >= texts.length) textTake = 0;
document.getElementById("homepage").innerText = texts[textTake];
textTake++;
});
Here is a starter for you:
const homepage = document.querySelector('#homepage');
let html = [
"hello what's your name?",
'my name is <br> <input id="name"> <br> <button> submit </button>'
];
document.addEventListener('click',function(){
if (html.length) {
homepage.innerHTML = html.shift();
};
});
I have a page with a variable number of modals. When a modal is shown I add a click event to the button on the modal. When I click the button the event is fired and the next modal is shown. However, on the second modal, nothing is fired when I click the button.
Any thoughts as to why the event listener wouldn't fire on a second click.
This is the code to add the event listener to each modal. onSubmission is the function that does some ajax stuff and hides the current modal, then shows the next modal.
function addSubmitAction(formId) {
console.log(formId);
document.querySelector('#modal-submit').addEventListener('click', function _listener() {
onSubmission({ 'id': formId });
document.querySelector('#modal-submit').removeEventListener('click', _listener, true);
}, true);
}
may be u need get click event on root node?
document.addEventListener('click', ({target}) => {
if( target.id !== submitId ) return;
/// your logic
});
example
$(":input").on("change", function(e) {
console.log("change triggered");
$("#section").html("<button id='order'>Order</button>");
registerButtons();
});
function registerButtons() {
$("#order").on("click", function(e) {
console.log("click triggered");
alert("Hello World");
});
$("#order").on("mousedown mouseup", function(e) {
console.log(e.type + " triggered");
});
}
registerButtons();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" value="123"/>
<div id="section">
<button id="order">Order</button>
</div>
I have a web page with a button and some input fields.
On the button an click event is registered
On the input fields an change event is registered
The onChange will trigger an AJAX server call, and the result will replace parts of the web page - including the button. After AJAX result is processed, all listener are registered again.
Now the problem. A user changes the value of an input field, and clicks directly the button - but to slow (lets assume the user needs 500ms for the click), so the onChange event is fired and the page is "updated/replaced". Now the "old" button fires an onMouseDown and the "new" button fires an onMouseUp event - but no onClick.
My current workaround is, to register the two mouseDown/mouseUp events, get the timestamp of the mouse down, and if the mouse up comes in 2 seconds, do what should be done by the onClick.
It is no option to remove the button part from the AJAX response - in worst case the button could be removed and replaced by an user info.
My hope is, that there is a better solution... any ideas?
You can take advantage of the event delegation and set your listener on the container instead of the button.
You are adding a click listener to your old button and your adding a new button to the dom. So the click won't work.
The button wasn't working because for some reason it can't focus when you hover over it. So I added a getFocus method and now it should work.
$("input").on("change", function(e) {
console.log("change triggered");
$("#section").html("<button id='order'>Order</button>");
});
function registerButtons() {
$('#section').on("mouseup", '#order', function(e) {
alert('Clicked!');
});
}
registerButtons();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" value="123"/>
<div id="section">
<button id="order">Order</button>
</div>
I just found out that jQuery provides a sweet API that can be used for event delegation. This way we don't have to manually check for event target. Check it out http://api.jquery.com/on/
$("input").on("change", function(e) {
console.log("change triggered");
$("#section").html("<button id='order'>Order</button>");
});
function registerButtons() {
$("#section").on("click", '#order', function(e) {
console.log("click triggered");
alert("Hello World");
});
$("#section").on('mouseover','#order', function(e){
$(this).focus();
});
}
registerButtons();
I'm attempting to prevent a user from clicking a link and it going to another page while any input is focused. Sometimes the only available space around the input and the keyboard is a link and some users click the link accidentally. I'm trying to make it so when they click the link it blurs the input (closes the keyboard) and prevents the page from following the link. Then let them click the link again if they want to go to another page after the input is no longer in focus.
html
<input type="text">
Example
I've tried the following...
jQuery
$('a').on('click', function (event) {
if ($('input').is(":focus")) {
console.log('focused');
event.preventDefault();
}
});
(nothing gets logged)
Also tried this...
if ($('input').is(":focus")) {
$('a').on('click', function (event) {
event.preventDefault();
$('input').each(function(){
$(this).trigger('blur');
});
});
}
Neither one prevent the page from going to whatever link was clicked...
I don't think you can do this. You can disable the click event on the links while input is focused, and enable it back again when blur occurs on the input elements. However, while if user clicks on a link while focused on the input element blur event will occur first (which would enable clicking) then click even occurs and links acts as normal.
You could try disabling the links while input elements have focus, then you can enable them on the first click and restore normal operation.
$("input").on("focus", function() {
$("a").on("click", function (event) {
event.preventDefault();
$("a").off();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" />
example
I think I found a solution.
HTML
Example.com
jQuery
$('input').on('focus', function () {
$('a').each(function(){
$(this).addClass('cant-click');
});
});
$(document).on('touchend', function (e) {
if (!$(e.target).closest('input').length) {
$('a').each(function(){
$(this).removeClass('cant-click');
});
}
});
CSS
a.cant-click { pointer-events: none; }
When the input takes focus, every link gets this class. When anything on the page is clicked that is not an input, it removes this class from every link.