(This is a jQuery/JS question)
I have +/- buttons for product quantity on an eCommerce site.
A click on those, changes the value of a number-input field and then triggers change event for this number-input field (with quantityInput.change()), which in turn triggers an ajax to update the cart.
I want to give a chance to the user to click the buttons several times before triggering the ajax.
I now use setTimeout to delay the ajax which made the user experience a little bit better, but this is only a half solution as eventually the ajax is triggered as many times as the buttons had been clicked - and this is redundant.
I'm looking for a way to trigger the ajax only on the "last" click - for example, the click which has no subsequent click for 3 seconds.
For example, if the current quantity for a product "Apple" is 1, I want to allow the user to make 3 fast clicks to change it to 4, and only then trigger an ajax to update the cart.
Again, the flow:
Click on +/- buttons ->> number-input value is updated ->> a change event is triggered (with quantityInput.change()) ->> an ajax is called.
Thanks,
Asaf
You're almost there - on every click, also use clearTimeout to clear the existing timeout, if there is one, to ensure that the timeout callback runs only once there have been no clicks for 3 seconds. For example:
let timeout;
quantityInput.on('change', () => {
clearTimeout(timeout);
timeout = setTimeout(someFnThatUsesAjax, 3000);
});
(make sure timeout is persistent and outside the handler)
Related
I have Jquery latest connected and working with other parts of application.
0. End goal: for a modal window to appear on the screen.
1. I click on a button.
2. A function runs that append a modal to body
3. With modals, in order for this modal to actually show on the screen, I
need to
press a button that has data-target="#EnterModalNameHere"
4. I make a hidden button in index.html that has the needed data-target
property.
5. I would like to be able to click this hidden button once the function in step
2 finishes appending the modal.
How can I tell Javascript "once finished appending modal, click on hidden button"?
You can create an Event.
You can create a custom Event which would be dispatch (trigger) immediately after
the document is ready.
So, in your situation, since you aren't using a media query, you can use :
SetTimeout like setTimeout(() => { do something }, timeout);. So, the timeout could be 1000 - which means 1sec and so on,
A custom event which you can trigger when the modal successfully appended to the body.
An Event Listeners Like load window.onload = function() { enter code here }
I'm creating a web form using AngularJS. This form contains, among other things, three buttons that, when clicked, sort the list items in an unordered list in 3 different ways. I've observed some weird behavior during a lag spike, whereas clicking another of these 3 buttons while the first's method call is still in flight causes a race condition that messes up the unordered list. In order to prevent this, I'm trying to make each of these 3 buttons disabled during the period of time when any of their onClick functions are running.
To really push this fix to its limits, I have automated tests running that are designed to click between two of these buttons alternately and repeatedly. The idea is that, even with the test software clicking between the two buttons at super-human speed, the second button will not be clickable while the first button's method call is in flight.
I've tried several methods to do this - using the ng-disabled property on each button, tied to a scope-level variable that each method toggles to true and false at the beginning and end of their methods, manually disabling the buttons at the beginning and end of each function - and yet in each case, the test reports that the race condition is still being triggered.
Considering that I'm manually disabling these buttons at the very beginning of their method calls, it appears that even this isn't enough. Does anyone know the absolute earliest point where I can disable the button after it's been clicked?
Theorem:
The problem you are having is that the script that is running effectively queues the click. The browser window is unresponsive as long as the event handler is running, but the click is still recorded, and processed as soon as the handler is done,
So what you do is
In handler1:
Disable button2
Do all the processing
Enable button 2
Only after that, the click is processed (even though you clicked it during the event handling). Because button2 is enabled at that time, handler2 will also run.
Proof:
With a piece of HTML, you can check that:
<button id="test1" onclick="window.test1();">Test1</button>
<button id="test2" onclick="window.test2();">Test2</button>
And script:
window.test1 = function()
{
document.getElementById('test2').disabled = true;
for (var i=0; i<1000000000; i++);
document.getElementById('test2').disabled = false;
alert('Test1 done'); // Notice: Alert after enabling button 2.
}
window.test2 = function()
{
document.getElementById('test1').disabled = true;
for (var i=0; i<1000000000; i++);
alert('Test2 done'); // Notice: Alert before re-enabling button 1.
document.getElementById('test1').disabled = false;
}
Two buttons, each of them will execute a similar, time consuming script. If you click button 1 and then quickly button 2 while the loop is running, you will notice that both handlers are called, but also you'll see that the other button is not (visually) disabled during the loop, because the signal to disable the button is also processed later, just like the click event.
If you press button 2 first (in which the message box comes before enabling the other button), you will notice that button 1 is not disabled while the loop runs, but it is disabled before the message box shows, and will remain so until after the message box is closed.
http://jsfiddle.net/u334tz36/1/
So, I think there is nothing to solve. Actually the two event handlers don't run at the same time but after each other, so there probably isn't even a problem at all.
Solution:
If you still think this is anoying and you want to silently consume the clicks, you can do this using a timer. In the following code, the button is not enabled in the handler, but in a timeout that runs 1ms later. That way, once the event handler is done, the (responsive) window will process all the delayed messages. Button 2 will be displayed as disabled, the click is consumed (and discarded) by the disabled button, and 1ms afterwards, the button is enabled:
window.enableTest2 = function()
{
document.getElementById('test2').disabled = false;
}
window.test1 = function()
{
document.getElementById('test2').disabled = true;
for (var i=0; i<1000000000; i++);
setTimeout(window.enableTest2, 1);
}
http://jsfiddle.net/u334tz36/2/
Fun thing is, you just have to give the window the opportunity to prosess the messages that are sent when you click the button. To do this, you don't need seconds at all, 1 millisecond will be enough, and you could even do with less. All you need is to change the order of events: first process all updates that relate to disabling the button and then perform the event handler. Since setTimeout also is message based, it also relies on the same update mechanism (and can actually be delayed by running code. So basically what you do by setting a timeout, is to put the code in the timeout at the end of the queue, no matter how short the given delay is. It's not a matter of time, it's a matter of execution order.
So, that is a possible way to solve it, but like I said, I don't think there is a problem in the first place.
I've got a table with dozens of rows (up to 100), and each row has 1 element with a mouseover event attached to it. On mouseover, I open a tooltip and need to make an AJAX request to fill it with some data.
My problem is fairly simple: if the user moves his mouse up and down over all the elements that have that event attached, I'm firing tons of requests at a time. I wanna throttle it one way or another, but I'm unsure how to.
I'm gonna have to check whether that same event has been executed in the last n seconds, but how do I keep a link between the firing of event 1 and firing of event 2?
You need a flag in the start of your AJAX call, if the flag is ZERO, return from the function. How you scope the varialbe is up to you.
if(AJAXOK==0) {
return;
}
AJAXOK = 1;
Set the variable in the AJAX call, so that is resets itself after a timeout:
window.setInterval(function() { AJAXOK = 1 },5000);
AJAXOK = 0;
If you're interested in trying a different approach, reactive extensions are designed for exactly this sort of thing:
http://reactive-extensions.github.com/RxJS
I have a function, that adjusts element width/height on a page. This function is triggered by a custom dimensionchange event.
I'm
$(window).trigger("dimensionchange")
whenever I'm loading content via AJAX or changing a page (I'm using jquery mobile).
My problem is on some pages, a bunch of Ajax requests get triggered (like a search page, which ajax loads criteria and intial results), so I'm ending up with several "dimensionchange" events, which all trigger my layout update function. This slows down the page considerably and is not necessary, because I only need to capture the last dimensionchange and then update the layout.
Question:
Is there a way to capture the last occurence of an event when the event fires a random amount of times? The only thing I could think of is to set a timeout on every event occurence and if there is no further event in ... 500ms... trigger the page update. But this seems pretty awkward, so I'm curious to know if there is a better way?
Thanks for help!
You want to use jQuery's Global Ajax Event Handlers ajaxStart() and ajaxStop() methods.
There is another recent post about Using AjaxStop and AjaxStart. The main thing you need to know is that you can be notified when the first ajax query begins, and when the last one ends. You could set a flag like this:
$(document).ready(function() {
var ajaxBusy = false;
$(document).ajaxStart( function() {
ajaxBusy = true;
}).ajaxStop( function() {
ajaxBusy = false;
});
});
jsFiddle
I use a customized drop-down menu which runs on jQuery events and animations.
The problem occurs when I activate the drop-down via mouseenter several times, which results in the menu sliding down then sliding up several times. I tried to fix it by adding .stop(true), which was successful, but it resulted in other problems like this.
I followed that advice(jsFiddle Here), but it causes more unattractive problems.
I need is a way to stop a function from firing redundantly, but still be able to stop a "slide down" immediately and then "slide up" if the user triggers .mouseleave.
I tangled with custom queues for a good 5 hours, with no success :(
Any ideas, advice, and criticism is welcome.
Basically it boils down to delaying the execution of the event handler.
var mouseoverTimer = null;
$('.elem').mouseover(function(){
clearTimeout(mouseoverTimer); //ignore previous trigger
mouseoverTimer = setTimeout(function(){ //wait to execute handler again
//execute actual handler here
}, 10);
});
If the same handler was called within the specified interval the pending execution is cancelled and queued again to execute 10ms later hoping that there's no subsequent trigger within that interval.