I have a problem with queuing up events in jQuery. I have an elevator project that allows the user to click on buttons, and then lights go on and then numbers change. That works fine, except when they punch a number again before it reaches the floor picked the first time. I want it to get to the floor first picked before it goes to the second clicked floor (or third, or fourth, etc.). I've done some stuff with .promise, when done, etc. and none of it seems to work.
I am using .click which appears to be the issue, because it fires the function regardless of where it is currently. Trouble is that I can't seem to find any alternative and it needs to finish current operation first before moving on to any other floors.
I hope I explained this well. If not please let me know. Perhaps there is another way entirely of doing it. Still learning this front end/jQuery stuff.
$( ".button" ).click(function(event) {
// doing stuff here....
$( runMainscript() ).promise().done(function() {
runMainscript(buttonclicked, floorQ);
});
});
function runMainscript(buttonclicked,floorQ) {
//doing stuff here
}
BTW, here is a timer for 2 seconds on each floor.
JSfiddle: http://jsfiddle.net/ak25Lxab/1/
See how if you click on two buttons quickly, it jumps around?
The deferred object works slightly differently. You should explicitly declare a deferred variable like this:
var dfd = new $.Deferred();
And when you want to fire done callback, you should call:
dfd.resolve();
So your queueing part of the script now looks like this:
$.when(dfd.promise()).done(function() {
dfd = new $.Deferred();
var onfloor = $("#onfloor").text();
runMainscript(buttonclicked, floorQ, onfloor);
});
And inside runMainscript you resolve this dfd deferred when elevator arrived to the floor.
See demo. Now, all floors are in the queue using deferred object.
I'm not an expert in deferreds, so maybe you can optimise this script further.
I don't really understand your problem and your jsfiddle is not working for me but as far as I can see you want to stop listen for the click event when the elevator is moving.
To do this you can stop listening for the click event and then restore the listener.
http://api.jquery.com/off/
So ideally, listen for the click event, as soon as it's fired stop listening for the click event, do your operations and then restore the listener on the click event for the .button
Or you can try to do something like this, put a state and do nothing if the state is not cleared:
jQuery - How can I temporarily disable the onclick event listener after the event has been fired?
Related
I'm trying to skip a delay event in JavaScript. Say( If I mouse wheel for 4 times continuously the first one ill get fired followed by the second, third and fourth one. In my scenario if the first event fired and when the second/third/fourth events are in delay or slow I want to speak the second and third event getting fired and must directly fire the final event (say fourth event))
Is this possible using JS/Jquery! And can anyone suggest me some sample for it if possible!
Sorry if I don’t make much sense, I am a beginner here.
It sounds like you're describing a debounce function, which will fire on the first event but merge subsequent events within a defined timeframe.
This plugin should achieve what you're looking for: http://benalman.com/projects/jquery-throttle-debounce-plugin/
This question and answer may also be helpful.
Based on the autocomplete example on this page, http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/, the final (4th in your example) event should be fired, but any intermediate events that happen in quick succession will be skipped.
Here is a Stackblitz example, debouncing a mousewheel event to every 0.1s. You simply need to include the plugin and then do:
$(document).ready(function () {
$('body').bind('mousewheel', $.debounce(100, debounceEvent));
function debounceEvent(event) {
// Process mouse wheel event here
console.log(event);
}
});
If you do a quick scroll, only the last event should be emitted.
im looking for some javascript events that trigger at the start and at the end navigating via dragging on flot plots so that i can do some ajax updates, however, I've been looking around online for some code to help me. I've found a few things, most didn't work worked or had bugs.
The best thing I've found so far is an answer from DNS, however it has unintentional behavior, when you hold the mouse click button down and stop panning the event triggers.
var delay = null;
element.on("plotpan", function() {
if (delay) clearTimeout(delay);
delay = setTimeout(function() {
// do your stuff here
delay = null;
}, 500);
});
The navigate plugin should really pass the event on to you; then you could easily check the state of the mouse buttons in your handler.
Since it doesn't, you'll need to attach your own mousedown/mouseup listeners to the overlay canvas; the child of your plot placeholder with class 'flot-overlay'. You can use these to update a shared variable with the state of the left button, then check that value in your handler above.
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.
Is there any way to know, in a jQuery onmouseup handler, if the event is going to be followed by a click event for the same element?
I have an event handler for a menu hyperlink which unbinds itself when the user either clicks on an element or "drops" (as in drag-n-drop) on an element. I want to avoid prematurely unbinding the handler on mouseup if a click is coming next.
I realize I can track mousedown and mouseup events myself or otherwise hack up a solution (e.g. wait 50 msecs to see if a click comes soon), but I was hoping to avoid rolling my own implementation if there's something built-in for this purpose.
There is nothing built-in because it's really specific to your needs. Thus, there would kilometers of code and documentation to maintain if jQuery would handle any combination of clicks, long clicks, moves, etc.
It's also hard to give you a snippet that satisfies your needs, but a setTimeout is usually the first step to take, with something like that :
obj.mouseup = function (){
obj.click = action; // do action
setTimeout ( function() {
obj.click = functionOrigin // after 500 ms, disable the click interception
}, 500);
};
you can use $(selector).data('events') for that
$('div').mouseup(function(){
if($(this).data('events').click){
console.log('Has a click event handler')
}
});
So I'm using YUI to add some animations in my application triggered when a user clicks certain elements. However, I'm running into a common problem that is easily fixed with some poor coding, but I'm looking for a more elegant solution that's less error-prone.
Often, when the user clicks something, a DOM element is animated (using Y.Anim) and I subscribe to that animation's 'end' event to remove the element from the document after its animation has completed. Pretty standard stuff.
However, problems arise when the user decides to spam-click the element that triggers this event. If the element is going to be removed from the DOM when the animation ends, and the user triggers an event handler that fires off ANOTHER animation on the same element, this 2nd animation will eventually cause YUI to spit really nasty errors because the node it was animating on suddenly disappeared from the document. The quickest solution I've found for this is to just set some module/class-level boolean state like 'this.postAnimating' or something, and inside the event handler that triggers the animation, check if this is set to true, and if so, don't do anything. In the 'end' handler for the animation, set this state to false.
This solution is really, really not ideal for many reasons. Another possible solution is to detach the event handler for duration of the animation and re-attach it once the animation is complete. This is definitely a little better, but I still don't like having to do extra bookkeeping that I could easily forget to do if forgetting to do so leads to incomprehensible YUI errors.
What's an elegant and robust way to solve this problem without mucking up a multi-thousand-line Javascript file with bits and pieces of state?
Here's some example code describing the issue and my solution to it.
var popupShowing = false,
someElement = Y.one('...');
someElement.on("click", showPopUp)
var showPopup = function(e) {
if(!popupShowing) {
popupShowing = true;
var a = new Y.Anim({
node: someElement,
duration: 0.2,
...
});
a.on('end', function() {
someElement.remove(true);
popupShowing = false;
});
a.run();
}
}
So if the user clicks "someElement" many times, only one animation will fire. If I didn't use popupShowing as a guard, many animations on the same node would be fired if the user clicked quickly enough, but the subsequent ones would error out because someElement was removed when the first completed.
Have a look at the Transition API. It's more concise, and may very well do what you want out of the box.
someElement.transition({ opacity: 0, duration: 0.2 }, function () { this.remove(); });
// OR
someElement.on('click', function () { this.hide(true, { duration: 0.2 }); });
// OR
someElement.on('click', someElement.hide);
Personally, I haven't used Anim since Transition was added in 3.2.0. Transition uses CSS3 where supported (with hardware acceleration), and falls back to a JS timer for older browsers.
http://developer.yahoo.com/yui/3/examples/transition/transition-view.html
Edit: By popular demand, a YUI way:
myAnim.get('running')
tells you whether an animation is running. To use this you might have to restructure the way you call the event so the animation is in the right scope, for example:
YUI().use('anim', function (Y) {
var someElement = Y.one('...');
var a = new Y.Anim({
node: someElement,
duration: 0.2,
...
});
a.on('end', function() {
someElement.remove(true);
});
someElement.on('click', function() {
if (!a.get('running')) {
a.run();
}
});
});
jsFiddle Example
Previously I had said: I personally like the way jQuery handles this. In jQuery, each element has a queue for animation functions. During animations an "in progress" sentinel is pushed to the front for the duration of the animation so anything that doesn't want to step on an animation peeks at the front of the queue for "in progress" and decides what to do from there, e.g. do nothing, get in line, preempt the current animation, etc.
I don't know enough about YUI to tell you how to implement this, but I find it to be a very elegant solution.
Quick & dirty solution to this particular issue?
Attach your handlers using .once() instead
someElement.once("click", showPopUp)
Also suitable if you need the handler re-attached later, just call that line again when the animation is done. You could also store your state information on the node itself using setData/getData but that is just a panacea to the real problem of state tracking.
Also, +1 to Luke's suggestion to use Transition for DOM property animation, it's grand.