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();
};
});
Related
I have created an input with a button that when I click on button, input show and remove. But I also want to remove input when I click on DOM, and I know I should set addEventListeners to DOM. But I don't know what function I should use.
//Html
<div class="search">
<input type="text" class="input" placeholder="Search . . ." />
<button class="btn">
<i class="fas fa-search"></i>
</button>
</div>
//Js
const searchSection = document.querySelector(".search");
const input = document.querySelector(".input");
const searchBtn = document.querySelector(".btn");
searchBtn.addEventListener("click", () => {
searchSection.classList.toggle("active");
input.focus();
});
The vanilla JS way to listen for click events is listen for all clicks on the document, and then check if the clicked element has the selector you care about.
document.addEventListener('click', function (event) {
// If the clicked element doesn't have the right selector, bail
if (!event.target.matches('.click-me')) return;
// Don't follow the link
event.preventDefault();
// Log the clicked element in the console
console.log(event.target);
}, false);
This approach is called event delegation, and it works by taking advantage of something called event bubbling.
You can read more on Listening for click events with vanilla JavaScript
Basically I have a list with members of your team. For every member there is an individual div, to select a member you click on the div. I have added an on click event handler on the div so that on click it selects that specific member and highlights it. I also have an edit button and a remove button inside the div for each member. However what is happening right now is that when you want to edit or remove a team member it also triggers the div onClick. I understand that this is expectd behaviour however I'm not sure how I can prevent the div onClick from firing when the buttons are clicked or how I can achieve the same 'look and feel' without putting the buttons in the div.
I want to keep the same look (a section for every teammember which can be clicked to select a team member) but I don't mind changing the structure of the div. I'm working in React if that matters.
Here's a simple example of how you stop the clicks bubbling up to the parent:
const Button = () => (
<div
onClick={() => {
console.log("I won't trigger if you click the inside div");
}}
>
<div
onClick={event => {
event.stopPropagation(); // <-- this stops the click going through to the parent div
console.log('Thank you for clicking the inside div');
}}
>
I'm Inside
</div>
</div>
);
Change the onClick to:
onClick = (event) => {
//event.target includes the specific element which was clicked.
if(event.target.id == '<YOUR-DIV-ID>'){
//handler
}
}
$(":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 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.
I have a problem which I don't know is related to the meteor implementation of events or to Javascript events in general.
I have a textbox attached to a "change" event.
Next to it, I have a button attached to a "click" event.
When I do a change in the textbox and click the button, the click event does not fire (only the change event does). So I have to click the button two times for the click event to fire.
In Firefox, it works if I attach a mousedown event instead of the click event to the button. In Chrome it doesn't work either ways.
Minimal code reproducing the problem:
JAVASCRIPT: testevent.js
if (Meteor.isClient) {
Session.set("something", "something");
Template.hello.foo = function() {
return Session.get("foo");
};
Template.hello.something = function() {
return Session.get("something");
}
Template.hello.events({
'click .buttonid' : function () {
console.log("click !");
},
'change .textid' : function (e,t) {
console.log("change !");
var bar = e.target.value;
Session.set("foo",bar);
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
HTML: testevent.html
<head>
<title>testevent</title>
</head>
<body>
{{> hello}}
</body>
<template name="hello">
<input type="text" class="textid" value="{{foo}}"/>
<input type="button" class="buttonid" value="{{something}}" />
</template>
When I replace class with id the click event fire, but when I have multiple fields with the same id the events work only on one field.
The issue has to do with the hello.foo:
Template.hello.foo = function() {
return Session.get("foo");
};
and the fact that the value of foo is used to reactively populate the text input. If you remove the hello.foo function everything works as expected. When the user clicks the button, the change event fires which sets the "foo" session variable which in turn causes the template to re-render. I think the rendering process clears the remaining event queue, so the click handler never fires.
There are a couple of ways you can fix this. An easy (but crude) way is just to delay setting the session variable in the change event handler. For example:
Meteor.setTimeout(function(){Session.set("foo", bar);}, 100);
Obviously you would need to choose an appropriate delay and that may be browser/data dependent. Alternatively, you can just put the text input in its own template. For example:
<template name="hello">
{{> helloText}}
<input type="button" class="buttonid" value="{{something}}" />
</template>
<template name="helloText">
<input type="text" class="textid" value="{{foo}}"/>
</template>
After binding the events properly to this new template, you will find that helloText will be rendered separately from hello and thus your events will be preserved.