I have an input type="number" and am using the up/down arrows within the field to change the value of the input. I want to trigger a function after the final click/change of the input.
By final I mean after the input hasn't been changed for 1000ms (my assumption that the user has now stopped clicking).
I've set up a 1000ms setTimeout() that runs the function, but even though I'm calling clearTimeout() .on('change') of the input, the function runs 1000ms after the first change, rather than the last.
I've set up a simple JSFiddle to illustrate what I mean. The div with "Hello World!" in it should not appear until after the final click.
If you rapidly click the up arrow on the input (at least once every 999ms) then the div should never appear.
I have looked through a lot of other similar questions on here but they're almost all about the scope of the timer variable, which I don't think applies here.
What am I doing wrong?
onchange, is triggered when input loses its focus, try on input.. btw. jquery is not required here.
var timeOut;
document.getElementById("foo").addEventListener("input", function() {
clearTimeout(timeOut);
timeOut = setTimeout(function() {
document.getElementById("bar").style.display = "block";
}, 1000);
});
Related
I have a form with two input elements that are somewhat intertwined. In element#1 (element #2 is right after element#1 in the tabindex order), once the user tries to leave that field, I run an ajax call to check if the value entered is already in the database and if so, use the javascript confirm dialog to ask the user a question. The second element, upon gaining focus, automatically pops up a modal window with choices the user can make. I am using Jquery.
I would like to run the "Does this data exist" ajax call as soon as the user leaves the first element. the Blur event seemed to be what I wanted as this existing data check is needed whether the user made a change or not.
My problem using blur, though, is that its handler runs AFTER the first element loses focus and focus jumps to element#2. So, the blur handler from element #1 pops up the confirm screen at the same time element #2's focus handler pops up the choices modal and I now have 2 popups open at the same time.
I would like to give the user the chance to answer the question in the confirmation alert before the choices for the element#2 pop up.
Is there a Jquery event similar to blur, but that runs just BEFORE focus is actually lost? Or, is there a way to prevent the next element from gaining focus until the blur handler from the first element completes?
Trying to stop propagation or preventDefault() in the Blur handler does nothing because the focus on element#2 has already happened before the blur handler runs.
I've tried setting the tabindex of element#2 to -1 and then programmatically focusing on that element when needed, but tabbing away from this element becomes a problem, and reverse tabbing skips it (jumping straight to element#1) - I still want that element in tabindex ordering, but just don't want it to gain focus until element#1 completes its handler that needs to run when it loses focus.
I have tried setting status variables as well but when I add code to handle the transition between the two elements, I end up with similar issues and it presents additional edge cases complexity. I've also tried messing with mousedown and keydown events and trying to prevent the default processing, but that added significant complexity and room for error as well.
Any ideas would be welcome. Thank you.
This solution is a bit of a hack, but accomplishes your goal. The trick is to place what amounts to a "no-op" element that accepts the focus on blur. Then controlling the tab after the AJAX request.
Upon each "blur" event, we test to ensure we capture the correct <input> element (I'll leave those details to you).
After the AJAX request has completed, then focus on the next <input>.
For this demo, type 2 in the second input, then tab. I added a short delay so you can see that it works.
$("input").on('blur', function(e){
if(this.value == 2) {
console.log("do ajax request");
setTimeout((function(){
$(this).next().next('input').focus();
}).bind(this), 500);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input tabindex="1" />
<input tabindex="2" />
<div tabindex="3"></div>
<input tabindex="3" />
Would something like this do the trick?
Have a variable that indicates if it's okay to show the second popup
let allowSecondPopup = true;
Have a variable that indicates whether showing the second popup was postponed
let secondPopupPostponed = false;
Set the variable when the first input receives focus
$("#input1").on("focus", fuction () {
allowSecondPopup = false;
});
Send ajax on blur
$("#input1").on("blur", function () {
//$("#input1").disabled(true);
//$("#input2").disabled(true);
$.post("https://example.com", { }, fuction (response) {
if (secondPopupPostponed) {
// Only show second popup after the ajax-call has finished
showSecondPopup();
allowSecondPopup = true;
secondPopupPostponed = false;
}
});
});
And when the second input receives focus, check the variable
$("#input2").on("focus", fuction () {
if (allowSecondPopup) {
showSecondPopup();
} else {
// We're still waiting for the ajax-call to complete.
// When the ajax-call completes, the callback will show the second popup.
secondPopupPostponed = true;
}
});
I'm using this Codrops Blueprint to create a quotes rotator. I modified the rotator to have a next button, powered by the code below:
_startRotator: function() {
if (this.support) {
this._startProgress();
}
var timeout = setTimeout($.proxy(function() {
if (this.support) {
this._resetProgress();
}
this._next();
this._startRotator();
}, this), this.options.interval);
$(".testimonial-next").click($.proxy(function() {
clearTimeout(timeout);
if (this.support) {
this._resetProgress();
}
this._next();
this._startRotator();
}, this));
},
I added the .click function below the setTimeout function, and added the var to the setTimeout function.
When .testimonial-next is clicked, the rotator's timer is reset and the code in the timer is instantly executed. As far as I can tell, the timer restarts itself, so I shouldn't have to add code to do this.
On the website where this is put to use (see the "Testimonials" section), however, there seems to be a problem. There should be five quotes, in the order of Kim, Lynn, Shannon, Jennifer, and Chris. If the timer runs without being interrupted, everything works as expected. If the Next button is clicked, certain quotes seem to be skipped. Other times, the quotes stop rotating or randomly rotate at a high speed.
What am I doing wrong?
Your button click handler is attached again and again to the button, making a click result in several executions of the same code.
To solve this you can best move that piece of code out of the _startRotator function and move it somewhere where it will only be executed once.
That way, when you click, there will be only one handler that gets executed.
Less nice, but also a solution, would be to keep the code where it is, but always first remove any existing click handler, before you attach it again:
$(".testimonial-next").off('click').on('click', $.proxy(function() {
// etc...
But this is really an ugly solution. Try to move the code.
Ok StackOverflow, riddle me this.
I have a button that I click on which toggles the visibility of an input. In the scope function which changes the visibility I use javascript to set focus on that input tag. What I want to know is why does it not work unless I wrap it in a setTimeout?
$scope.toggle = function() {
if ($scope.hideInput) {
setTimout(function(){
input.focus();
}, 0); // That's right, zero!
}
$scope.hideInput = !scope.hideInput;
};
Here's a working jsfiddle with a button that correctly sets the focus and a button that doesn't:
http://jsfiddle.net/PsS99/1/
Can tell you the reason why.
First you can't focus element, with css display:none.
So in the one (broken) method, you focus the element before it is actually displayed.
Because the angular will go line to line and $scope.hideInput = !scope.hideInput; will trigger the watcher for a digest-loop. In that loop your input will be set to display: block.
The timeout will move the focus command into it's own thread, and the $scope.hideInput = !scope.hideInput; will trigger the digest, too.
But the digest is curiously fast enought to display the element before the input.focus(); will be executed.
This is my explanation but understanding this, did help me in some curious problems of angular's timing.
Maybe use this ? http://ngmodules.org/modules/ng-focus-on
A directive to set the focus by variable.
I have some issues with my js code. I want to animate a simple click function so that a div, shows the div below but animates back after say 5 seconds. I think I got the right setup with fadeToggle and delay but I just don't get it how to set up "over-clicking" prevention. I mean when people mess with the click-object.
My first attempt was stop(true,true). Although it seems that it works as expected (aborting further function execution) it unfortunately shows the underlying div after 5 seconds although it should show the upper one (picture).
Here is the js and the fiddle:
$(function() {
$("#boxes li").on("click", function(){
$(this).find(".front,.back").stop(true, true).fadeToggle(800).delay(5000).fadeToggle(800);
});
});
but also a js fiddle link to see what I mean:
http://jsfiddle.net/sfiddle/bqbPL/
Regards,
PS: try first to click once to see what effect I want to accomplish and then click 2 times to see how after 5 seconds it will show the text div.
I have modified it a bit,
but still require some work on it, you may use some flag variable with click,
Please see the updated 'fiddle`, it handles the process but stores the next click that occurs after it fade back.
Update: to avoid double clicking
Creating a flag is, you will create a Boolean variable, that will be true/false. (or int variable with 0 or 1),
Like:
var flg=true;
Now, this variable called flag, flag is initiated with False/True value(as per requirement) then we will modify flag after the event occur(the event we want to watch out, here click of button) once event occurs we will change the flag.
In the second you will add flag to condition. if( condition == true && flag == true) {....} so, if flag is changed to false after event/click the event in if will not occur again.
I hope this will help..
I need to recognize a long click in a JavaScript bookmarklet.
So, I cannot use jQuery, neither onclick() event and similar. Is it possible, and how?
onmousedown, call setTimeout() for the duration of your long click. If the timeout is allowed to expire, it will call its function to do whatever you hoped to do on the long click. However, onmouseup you cancel the setTimeout() if it has not yet expired.
<script type='text/javascript'>
// t will hold the setTimeout id
// Click for 1 second to see the alert.
var t;
</script>
<button onmousedown='t=setTimeout(function(){alert("hi");}, 1000);' onmouseup='clearTimeout(t);'>Clickme</button>
Here it is in action in jsfiddle
Isn't a long click just a click where mousedown and mouseclick events are considerably long away from each other? In order to solve that you could just measure the time it takes from a mousedown event to the click event and check if it is, e.g. longer than two seconds (or whatever you desire).
You can access the current milliseconds since 01.01.1970 via new Date().getTime(). Given that I would intuitively check a "long click" like that.
$(".selector").mousedown(function() {
$(this).data("timestamp", new Date().getTime());
}).click(function(event) {
var e = $(this);
var start = e.data("timestamp");
e.removeData("timestamp");
if (start && new Date().getTime() - start > YOUR_DESIRED_WAIT_TIME_IN_MILLISECONDS) {
// Trigger whatever you want to trigger
} else {
event.preventDefault();
event.stopPropagation();
}
});
Late reply, but instead of click / long click to provide two different actions, you might want to consider click / double click.
First click: Record time and then timer to perform action1 in 500 miliseconds.
Second click: If time since last click is short, cancel timer and perform action2. If time since last click is long, then this is a first click.
Nothing stops you from using triple click, etc.