How to close input when click on document in vanilla javascript - javascript

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

Related

If repeated triggering of click events is prohibited through javascript, resulting in repeated API requests

I am a front-end novice. There is a need for users to click the button to get points. When the button is clicked, an API will be triggered, but I am worried that the user will repeatedly send API requests to the backend if the user clicks too fast. At present, my knowledge only knows that it can be written as in the example. I would like to ask if there is a better or safer way? thanks
let btn = document.querySelector("#btn");
btn.addEventListener('click', function(e) {
console.log("Receive point")
btn.setAttribute('disabled', true)
})
<button id="btn">Receive points</button>
You can remove event listener using removeEventListener after first click instead of disable button attribute.
Example:
window.addEventListener("load", () => {
document.getElementById("btn").addEventListener("click", removeclick);
});
function removeclick() {
console.log("Clicked 1 time . No new event fired.");
document.getElementById("btn").removeEventListener("click", removeclick);
}
<button id="btn">Receive points</button>
Or use third parameter once:true of addEventListener, which allow the event listener to run only once.
Example:
var element = document.getElementById("btn");
element.addEventListener('click', function(e) {
console.log("Clicked 1 time . No new event fired.");
}, {
once: true
});
<button id="btn">Receive points</button>

Handling the eventlistener

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();
};
});

Why does event bubbling not work?

I thought I understand event bubbling but my code does not work as expected:
<div id="write">
<form method="post" tabindex="1" onsubmit="myfunc()">
<textarea></textarea>
<input />Another form element
<input />Another form element
<input type="submit">
</form>
</div>
<p>Some other text and images...</p>
<div id="overlay"></div>
<script>
//var formele = document.querySelectorAll("#write form, #write form *");
var formele = document.querySelectorAll("#write form");
for (var i = 0; i < formele.length; i++) {
formele[i].addEventListener("focus", function () {
overlay.classList.add("active");
});
formele[i].addEventListener("focusout", function () {
overlay.classList.remove("active");
});
}
</script>
This code should darken the rest of the page when the form or an element inside gets focus or is clicked. I understood event bubbling in the following way:
When a child of the form gets focus it has no event listener added. Thus the focus event bubbles up to the form element and triggers it's event listener.
However it doesn't work that way: If I add the event listener to the form only nothing happens when a textarea or input inside is clicked. I have to add event listeners to the child elements too in order to get it work.
Can anyone explain? Obviously my understanding of event bubbling is wrong somehow.

jQuery - Replacing HTML element multiple times

I want to replace a button with an input field, where the user enters something and presses the enter button. After that, the button from the beginning should appear again. My script works so far but I can't repeat this once it finished.
Update: The button should also appear again, if the input field is shown but the user don't want to enter anything and clicks somewhere else.
The code:
<button id="createButton">Create item</button>
/*
jquery stuff
*/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('#createButton').click(function( event ) {
$(this).replaceWith('<input type="text" id="buttonInput" placeholder="e.g. books, movies" autofocus>');
});
$(this).on('keypress', function (event) {
if(event.which == '13'){ // If enter button is pressed
alert('You entered something');
$('#buttonInput').replaceWith('<button id="createButton">Create item</button>');
}
});
});
</script>
Update 2: I updated the code with hide() and show() to get the same result. But how can I let the input disappear, if the user clicks somewhere inside the body, without redundancy?
The new code:
<button id="createButton">Create item</button>
<input type="text" id="input" placeholder="e.g. books, movies" autofocus>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
$('#input').hide();
$(document).on('click', '#createButton', function (event) {
$(this).hide();
$('#input').show().focus();
});
$('#input').on('keypress', function (event) {
if (event.which == '13') { // if enter button is pressed
$(this).hide().val('');
$('#createButton').show();
}
});
});
</script>
As the other answers say, you're replacing the element (createButton), which means the click handler is no longer bound.
You can either re-bind, or bind to the parent element, with the #createButton selector using on.
$(document).on('click','#createButton', function( event ) {
...
});
Don't actually use document - use whatever the parent element is, which doesn't get replace (a div, perhaps?)
Replacing DOM elements is a bad approach though -- you'd be better off leaving the elements on the page, and using show and hide.
http://jsfiddle.net/v03j8bns/
Updated Answer
Here's a fiddle showing the show/hide/ approach. To handle:
The button should also appear again, if the input field is shown but the user don't want to enter anything and clicks somewhere else.
When the button is clicked, I call focus() on the textbox. I've also hooked up a blur() event handler, so if the user clicks/tabs out, then it'll hide the textbox and show the button.
You have to bind the click event to newly created button again:
$(document).ready(function () {
$('#createButton').click(function (event) {
$(this).replaceWith('<input type="text" id="buttonInput" placeholder="e.g. books, movies" autofocus>');
});
$(this).on('keypress', function (event) {
if (event.which == '13') { // If enter button pressed
//Disable textbox to prevent multiple submit
alert('You entered something');
$('#buttonInput').replaceWith('<button id="createButton">Create item</button>');
}
$('#createButton').bind('click', function (event) {
$(this).replaceWith('<input type="text" id="buttonInput" placeholder="e.g. books, movies" autofocus>');
});
});
});
You have this issue because you replace DOM elements. It means that your new element button no longer has click handler.
I would recommend you to use something like show/hide or use jQuery delegate on/bind for handling click.
When you're changing DOM on the fly and want to automatically assign listeners to elements that may or may not exist at certain points of time, you need to use delegated event listeners.
$(document).on('click', '#createButton', function () { ... });
$(document).on('click', '#buttonInput', function () { ... });
These handlers will work however you scramble the DOM.

Parent click events overlaps children click events

I want to be able to click the parent div, but have the child form and anchor elements be exempt from the click event.
<div class="root">
<div class="parent">
<div class="container">
Hello World
<div>
<span> Hello World Again
</div>
<form class="form">
<label> inputs
<input id="text" type="text"/>
<textarea></textarea>
<input id="submit" type="submit"/>
</form>
</div>
</div>
</div>
jQuery:
$(".parent").on("click", ".container", function() {
alert("Parent clicked");
});
$(".parent").on("click", "#text", function(event) {
event.preventDefault();
alert("Form Input clicked");
});
$(".parent").on("click", "#submit", function(event) {
event.preventDefault();
alert("Form Button clicked");
});
$(".parent").on("click", "a", function(event) {
event.preventDefault();
alert("anchor link clicked");
});
Clicking on any of the form elements (input, textarea, button submit) or the anchor tag won't work because the parent click event is firing.
How can I make the parent click event only on elements outside of the child form and anchor tag? The parent click event can cover any of the other children except those two elements.
You have two choices:
Hook the click event on the relevant child container (it looks like it would be the form) and use event.stopPropagation() within the handler. That will stop the event bubbling to the parent. Something like this:
// Option 1: Hook on the form and stop
// propagation (hooking up "false" does an
// implicit preventDefault + stopPropagation)
$(".parent").on("click", "form", false);
Inside the parent's handler, check to see if the parent element is the element that was the source of the event (e.target). If it is, process the event; if it isn't, ignore it, it was generated on a child element. Something like this:
$(".parent").on("click", ".container", function(event) {
// Option 2: Look at event.target and ignore
// the event if it originated in a descendant
// element
if (this === event.target) {
alert("Parent clicked");
}
});
Note that those do two slightly different things. The first one says "Prevent the parent from seeing clicks on the form" whereas the second one says "Ignore clicks that aren't directly on .parent .container". Either can be adapted, of course, with different targeting.
Live Examples:
Your original problem
Option 1
Option 2

Categories