I noticed my users sometimes click the buttons twice, maybe no one told them one click is enough.
What's the best way to prevent the double-click?
I basically hide the button and show a "loading" gif, but that apparently is not enough...
Usually disabling/hiding/replacing the button should work. If they are real fast, try setting a variable to false when your script starts, return if it's true, set it to true after the first click.
var alReadyClicked = false;
function click(){
if (alreadyClicked)
return false;
alreadyClicked = true;
}
Don't forget to set it to false when the user can click again.
If they are clicking fast enough to fire the double click event, return false.
ondblclick="return false"
EDIT: This will not cancel the single click event so problem would still exist.
I just found out the jQuery funcion .one(), that may be useful great for this kind of purpose! great!
The equivalence to JQuery .one() may be the once option on AddEventListner like:
function doSubmit () { /* your code */ }
btn = document.getElementById ('foo');
btn.addEventListener ('click', doSubmit, {once: true});
Reference: javascript - JS equivalent for jQuery one() - Stack Overflow
Another example using a flag
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>test dbl click</title>
</head>
<body>
<button id="btn1">Click Away</button>
<div id="out"></div>
<script type="text/javascript">
function addMessage( msg ){
document.getElementById("out").innerHTML += (new Date().toTimeString()) + " : " + msg + "<br/><br/>";
}
function singleClick(){
addMessage( "single");
}
function addDoubleClickProtection( element, fncToCall ){
var isClicked = false;
var timer = null;
element.onclick = function(){
if(!isClicked){
isClicked = true;
timer = window.setTimeout( function(){ isClicked = false; }, 200);
return fncToCall();
}
}
}
addDoubleClickProtection( document.getElementById("btn1"), singleClick );
</script>
</body>
</html>
Simple method by counting the submit button click and with minimum decoration will:
<script>
var click_count = 0;
function submit_once () {
document.forms.A.elements.cmd.forEach(
function(e,i,l){e.style.color="#888";});
return (click_count++ > 1);
}
function reset_count () {
document.forms.A.elements.cmd.forEach(
function(e,i,l){e.style.color="unset";});
click_count = 0;
}
</script>
<form name="A">
<button type="submit" name="cmd" value="doAdd"
onclick="return submit_once();">Do add</button>
<button type="submit" name="cmd" value="doDel"
onclick="return submit_once();">Do delete</button>
</form>
You can create a util function once which will take CB function. And all logic handles seamlessly. You don't have to create a global variable to count or update.
function once(cb) {
let once = false;
return (...args) => {
!once && cb(...args);
once = true;
};
}
// How to use it.
// Create/bind function
const log = once((data) => {
console.log(data);
});
// Use it
Promise.resolve("hellowold").then(log).then(log);
Above line print only once.
Related
The aim was to make a "run/stop" button completely unresponsive whilst in the "stopping" state (ie waiting for some code to reach a termination point.
Despite disabling click (mouse) handling use both element.disabled = true AND element.removeEventListener , i find that whilst the code is running with the click event supposedly disabled the browser still collects clicks and will fire events after the wait code ends and the even listener is re-enabled.
Example code :
fiddle here : https://jsfiddle.net/xjf26dpe/
<!doctype html>
<html>
<head>
<script type="text/javascript" src="js.js"></script>
</head>
<body onload="init();">
<button type="button" id="runstatus">Play</button>
</body>
</html>
var runstatus="stopped";//values 'stopped' , 'running', 'stopping'
function init() {
UIupdate();
}
//toggle button display text
function UIupdate(){
var t = document.getElementById("runstatus");
if ( runstatus == "stopped") {
t.innerText = "Run";
t.addEventListener("click",stopstart);
t.disabled = false;
} else
if ( runstatus == "stopping") {
t.innerText = "stopping..";
// t.removeEventListener("click",stopstart,);
t.removeEventListener("click",stopstart,true);
t.disabled = true;
} else
if ( runstatus == "running") {
t.innerText = "Stop";
}
}
function stopstart(){
var f,f2;
if (runstatus=="stopped"){
runstatus="running";
UIupdate();
} else
if (runstatus=="running"){
document.getElementById("runstatus").removeEventListener("click",stopstart);
f = function(){
runstatus="stopping";
UIupdate();
window.requestAnimationFrame(f2);
}
f2=function(){
wait();
runstatus="stopped";
UIupdate();
}
window.requestAnimationFrame(f);
} else
if (runstatus=="stopping"){
//nothing to do
}
}
function wait(){
var i,j=0;
for (i=0;i<1e10;i++){
if (i%1e9 ==0){
j++;
console.log("waiting to stop",j,"of 10");
}
}
console.log("finished");
return;
}
.. whilst the code is in the 'wait' function I find that clicking on the button will still stack click responses that are acted on when the wait code terminates. I want these clicks to be completely ignored
Please I want to create a button that can be clicked only once in 24hrs in js but I don't really know how to put it up.
<html>
<head>
<title>Disable Button</title>
<script>
function doSomething () {
document.getElementById("myButton").disabled = true;
document.getElementById("myButton").disabled = false;}
</script>
</head>
<body>
<input type="button" id="myButton" onclick="doSomething()"
value="Click Here To Do Something"/>
</body>
</html>
window.onload = () => {
//on load of the page it will check for same day and disable/enable.
let lastclicked = localStorage.getItem('lastclicked') || '';
document.getElementById("myButton").disabled = lastclicked === new Date().toDateString();
}
function doSomething () {
localStorage.setItem('lastclicked', new Date().toDateString());
document.getElementById("myButton").disabled = true;
}
you need to save to date and time of the last trigger somewhere in local storage or cookies so next when the button is triggered it checked the date in storage if that exists then it will check the date.
hope so it will work for you.
var todayclick = true;
var buttonval = document.getElementById("myButton");
buttonval.click(function() {
if (todayclick ) {
alert("Error!");
}
else {
variable += 1;
todayclick = false;
}
setTimeout(function() {
todayclick = true;
}, 86400);
});
EDIT the fact that I use closures and function is important. like the gatherData() and voteSection()
I want to click a div called submitButton this should tell me what the users have done. I have 3 sections. A voting section, a review section, and another type of voting section. the point is that right now I'm trying to set up the first voting section. When I click the submitButton I should get a an object that looks like {vote:down} or {vote:up} I only have two buttons in the voting section.
function gatherData(){
var submitButton = ".submitButton";
var result = {}
function voteSection(){
$(".upButton").click(function(){
// result.vote = "up"
// console.log(result) ;
$(this).data("clicked", true);
$(this).siblings(".downButton").data("clicked",false)
})
$(".downButton").click(function(){
$(this).data("clicked", true);
$(this).siblings(".upButton").data("clicked",false)
// result.vote = "down";
// console.log(result) ;
})
// return result;
}
$(submitButton).on("click",function(){
if($(".upButton").data("clicked")){
result.vote = "up"
}else if($(".downButton").data("clicked")){
result.vote = "down";
}
})
return result;
}
$(".submitButton").on("click",function(){
console.log(gatherData())
})
Thanks for any help
EDIT
I realized I forgot to call voteSection
here's what I have now. it return an empty object
function gatherData(){
var submitButton = ".submitButton";
var result = {}
function voteSection(){
$(".upButton").click(function(){
// result.vote = "up"
// console.log(result) ;
$(this).data("clicked", true);
$(this).siblings(".downButton").data("clicked",false)
})
$(".downButton").click(function(){
$(this).data("clicked", true);
$(this).siblings(".upButton").data("clicked",false)
// result.vote = "down";
// console.log(result) ;
})
if($(".upButton").data("clicked")){
result.vote = "up"
}else if($(".downButton").data("clicked")){
result.vote = "down";
}
// })
return result;
// return result;
}
return voteSection()
// $(submitButton).on("click",function(){
}
$(".submitButton").on("click",function(){
console.log(gatherData())
})
== UPDATE VERSION 2 == CLOSURE EXAMPLE
Here is a second version that uses a closure that returns a function that can be called to acquire the current state.
http://codepen.io/anon/pen/xOjaJL
Notice the event handlers only bind to the dom 1 time per call voteGatherer(), the result of calling voteGatherer() is a function that you can call when you need the state of the vote.
function voteGatherer()
{
var state = { 'vote': null }; // no vote selection made
$(".my-voting-button").click(function(ev)
{
var target = $(ev.target);
state[target.data("action")] = target.data("value");
});
return function()
{
return state;
}
}
var gatherer1GetState = voteGatherer();
$(".my-submit-button").click(function(ev)
{
$("#stateString").html(JSON.stringify(gatherer1GetState())) ;
});
==== VERSION 1
I threw together a code pen to help you manage state across these sections before you hit sumbit. Check it out.
http://codepen.io/anon/pen/bZrxRk
<button data-value="up" data-action="vote" class="btn btn-primary my-voting-button">Vote Up</button>
<button data-value="down" data-action="vote" class="btn btn-warning my-voting-button">Vote Down</button>
Notice the voting buttons are attributed with an action and value that is updated on the state object.
So when you click the vote up button, the state["vote"] value is set to "up". This can be applied to all of your fields. You can just add the "my-voting-button" class to other button (and maybe rename the class to something that better fits your use case).
Here is the javascript that updates the state object:
var state = { 'vote': null }; // no vote selection made
$(".my-voting-button").click(function(ev)
{
var target = $(ev.target);
state[target.data("action")] = target.data("value");
});
Now you have a state object that is fully populated, you can just sumbit that object with ajax back to your server. In my example I stringify it and write it out on the page.
$(".my-submit-button").click(function(ev)
{
$("#stateString").html(JSON.stringify(state)) ;
});
Below are three buttons and a div
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://code.jquery.com/jquery-3.1.0.slim.min.js" integrity="sha256-cRpWjoSOw5KcyIOaZNo4i6fZ9tKPhYYb6i5T9RSVJG8=" crossorigin="anonymous"></script>
<!--<script src="index.js"></script>-->
<title>repl.it</title>
</head>
<body>
<button class="upButton">up</button>
<button class="downButton">down</button>
<button class="submitButton">submit</button>
<div id="vote">vote goes here </div>
</body>
</html>
You could something like this to get the vote value given the previous html doc.
$( document ).ready(function() {
var result = {vote:""}
$(".upButton").click(function(){
result.vote = "up";
});
$(".downButton").click(function(){
result.vote = "down";
});
$(".submitButton").click(function(){
$("#vote").html(result.vote);
});
});
Can someone help me get started with a button timeout feature. All I want is a button (when clicked) it becomes inactive for 2 seconds. After which it is active again.
<input type="button" value="click" id="click" onclick="foo(this);"/>
function foo(obj) {
obj.disabled = true;
setTimeout(function() {
obj.disabled = false;
}, 2000);
}
LIVE DEMO
window.setTimeout on MDN:
Executes a code snippet or a function after specified delay.
Start of with:
<button>Click me!</button>
Add an event:
<button onClick="...">Click me!</button>
Now we need to put something in place of that ....
this can be used to mean "the button that was just clicked"
this.disabled can be set to true or false to disable (or re-enable) the button.
setTimeout(function() {...},2000); executes the anonymous function after two seconds have passed (or as near as the timer resolution allows).
Again, need to put something in the .... I've already told you how to re-enable the button.
Although, since this isn't terribly reliable inside anonymous functions, it's probably better to start with var t = this; and use t to mean the button.
With all that in place, you have:
<button onClick="var t = this; t.disabled = true; setTimeout(function() {t.disabled = false;},2000);">Click me!</button>
Done. I hope this explanation was helpful.
PS. To those who are against inline event handlers:
This is an example
The OP is a beginner
An inline event is good enough
The function setTimeout allows you to specify a function to be called after an amount of milliseconds has passed. In this case, I passed in an anonymous function, that is, a function that does not have a name that is used for the sole purpose of re-enabling my button after 2 seconds.
var mybutton = document.getElementById("mybutton");
mybutton.onclick = function() {
mybutton.disabled = true;
setTimeout(function() {
mybutton.disabled = false;
}, 2000);
};
Live example
You can use setTimeout() function in javascript. Something like
<html>
<head></head>
<body>
<input id="test" type="submit" value = "clickme" onclick="deactivatefunc()">
<script type="text/javascript">
function deactivatefunc()
{
var btn = document.getElementById("test");
btn.disabled = true;
var mytimer = setTimeout(activate,2000);
}
function activate () {
var btn = document.getElementById("test");
btn.disabled = false;
}
</script>
</body>
</html>
I am a beginner in javascript, can you tell me what's wrong with the below code?
I want this to invoke buttonPressed() when a button gets pressed. From buttonPressed() it should call changeColor1(), changeColor1() should change the text color of a paragraph, and start a timer to invoke changeColor2(). Similarly changeColor2() should also change the color and call changeColor1() once the timer expires.
<html>
<head>
<script type="text/javascript">
function changeColor2()
{
alert("2");
var v = document.getElementById("onet");
v.style.color = rgb(0,255,255); // this statement is not working
var t=setTimeout(changeColor1,3000);
}
function changeColor1()
{
alert("1");
var v = document.getElementById("onet");
v.style.color = rgb(255,255,0); // this statement is not working
var t=setTimeout(changeColor2,3000);
}
function buttonPressed()
{
alert("Hello");
changeColor1();
}
</script>
</head>
<body>
<p id="onet"> Hello how are you? </p>
<form>
<input type="button" value="Display alert box!" onClick="buttonPressed()" />
</form>
</body>
</html>
Do not invoke the function, pass the reference only:
var t=setTimeout(changeColor2,3000);
I think you want style.color not .color.
By the way... please tell us what the code is supposed to actually do and what is wrong initially.
You need to quote style property values-
v.style.color = 'rgb(255,255,0)';
1) I don't like the fact that you have two timeouts set. Just call one function and use a flag to toggle between the two options.
2) The parameter to setTimeout that you want to use is a function pointer (changeColor) not the result of a function call (changeColor())
var flag = false;
var t;
function changeColor()
{
var v = document.getElementById("onet");
if(flag){
v.color = rgb(255,255,0);
} else {
v.color = rgb(0,255,255);
}
flag = !flag;
}
function buttonPressed()
{
alert("Hello");
t=setInterval(changeColor,3000);
}
Not really knowing what it is you're trying to do, I can tell you that your button's onClick handler references a method name that isn't in your code. Judging by the names of your methods, I think you meant to put "buttonClicked" in there.
Nevermind, looks like you changed it while I was typing.
Instead of v.color = rgb(0,255,255); use v.style.color = "#0ff".