Stop pending actions for jquery debounce on keyup (And double keypress) - javascript

I have some code that is using a plugin called debounce.
Plugin information: https://code.google.com/p/jquery-debounce/
I've run into a problem where the keypress events still run after keyup event because of the delay from debounce.
For instance... if you were to double click spacebar, the function still runs even though you didn't hold it down for over a second.
It's hard to explain my issue. I basically need a stop() function to run after keyup event to stop any more text being appended.
Here is an example:
http://jsfiddle.net/cTZJU/133/
Code:
function appendFunc() {
$('.output').append('Keypress running');
}
//Debounce the function running too often
$(document).keypress($.throttle(appendFunc, 1500));
$(document).keyup(function() {
/**
* I want to stop any pending keypress actions.
* - Including double keypress
*/
});
Thank you very much in advance.

Use $(document).clearQueue(); in the function called on keyup.
$(document).keyup(function() {
$(document).clearQueue();
});
You will have to bind each event on the document as a queue then only you can use clearQueue.
You can do it like as follows:
$(document).queue(function(){
$(this).keypress(function(){ });
});

Related

Given an array of EventEmitters, listen for only the first event

In my code, I have an array of EventEmitter objects. I know that at some point, one of them will fire an event called launched.
I only want to listen for the first event fired by an emitter in this array, and ignore any subsequent events.
My current code is:
emitterArray.forEach(emitter => {
emitter.once('launched', () => { console.log('Event fired!') });
});
However, this will wait for every emitter in the array to fire the event once.
I want the program to end after the exactly one of the emitters has fired this event exactly once.
Note: Terminating the process with process.exit in the event listener is not an option.
In your module, you can initialise a global (top module level) flag to false and make every event handler to check for that flag.
if (flag) {
return
}
flag = true
console.log('Event fired')
Since node.js is single-thread, you shouldn't get any race conditions there and even when all the event handlers will get triggered, you can control which of them will actually run its code.
Hope this makes sense.

onChange / onInput alternatives?

I'm creating a typing test page and running into a small issue.
I'm trying to start the timer when the user types, and using onInput works, but the problem is that it registers every time I type into the textArea which causes the starttimer function to repeat itself.
onChange works but it only works after I click outside the page which makes sense, but is not what im looking for. I need the timer to start as soon as the user starts typing. Also with onChange the stop function works, but the timer starts after i click outside of the page.
Is there a JS event that fits what i'm looking for, or is there a way to change onInput or onChange to fix the problem i'm having.
JavaScript
document.getElementById("test-area").onchange = function () {
startTimer(1);
};
Thank you.
You need to listen to the input event because as you said change is only triggered after the input loses focus which is not what you want. You also need to handle the event only once.
document.getElementById("test-area").addEventListener("input", () => {
startTimer(1);
}, {once: true});
Note that this removes the event handler after it is fired. If you need to run it again you will have to register the event one more time. Maybe in your timer callback.
Try like this, In JavaScript, using the addEventListener() method:
The addEventListener() method attaches an event handler to the specified element.
document.getElementById("test-area").addEventListener("change", function () {
if(!this.value.length){
startTimer(1);
}
}, {once : true});
Have you tried onfocus ? its not exactly when they start typing but it works. Another option would be that you use onInput and on the clocks start function change a boolian -isRunning - to true. then put a if (isRunning) return. something like:
function start() {
if(isRunning) return;
isRunning = true;
}
and then change the boolian to false when you stop onChange
Some solutions:
Variant 1
Just create a flag:
var timerStarted = false; // Was the timer started?
document.getElementById("test-area").oninput = function () {
if(timerStarted) return; // If timer was started - do nothing
startTimer(1); // Else - start the timer
timerStarted = true; // Remember what we've started the timer
};
Variant 2
(A bit shorter)
document.getElementById("test-area").addEventListener("input", function () {
startTimer(1);
}, {once: true}); // Good thing about addEventListener
// With this it will run the event only single time
More here: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
Can you use JQuery? If so it has a method .one() which will execute the function only once. You can freely use keydown/keyup event handler then. For eg.
<script>
$(document).ready(function(){
$("#test-area").one("keydown", function() {
alert("hey");
});
});
</script>

Unable to unbind event listener - trouble with turbolinks caching

I'm binding then unbinding the ready event listener to the document.
$(document).bind("ready", readyEventHandler);
function readyEventHandler() {
// run some code
$(document).unbind("ready");
}
The code produces no errors and will work. However, my javascript is cached and duplicates the code so I'll end up with having this code run more than once if I go back and then forward a page in the browser. When this happens, the ready event listener is not called at all. Am I properly unbinding this event listener? I know the caching issue becomes problematic(it's own separate issue) but I just want to bind the ready event listener, have it run code, then unbind it.
Not so sure it will help, but here are my 2 cents - instead of trying to unbind the readyEventHandler - make sure that if you run the function once it will not run twice:
var readyHandlerRun = false;
$(document).bind("ready", readyEventHandler);
function readyEventHandler() {
if (readyHandlerRun) {
return;
}
readyHandlerRun = true;
// Rest of your code...
}
Another options that popped just now:
$(document).bind("ready", readyEventHandler);
function readyEventHandler() {
readyEventHandler = function() { }
console.log('ready');
// Rest of your code...
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
UPDATE (by #jason328)
After talking with Dekel he provided me the appropriate answer.
$(document).bind("ready", function() {
readyEventHandler();
readyEventHandler = function() { }
});
Elegant and works like a charm!
if you just would like to use an eventhamdler only once, you could use one instead of bind
$(document).one("ready", function() {
// code to run on document ready just for once
});

Defer, debounce or timeout an event

I have two events
cy.on('mousedown touchstart', 'node', function (event) {
// start
});
cy.on('mouseover tapdragover', 'node', function (event) {
// end
});
The problem is that the second event is almost immediately fired since the first event was fired when the mouse is being pressed on a node and the second is fired when the mouse is over a node.
Is it possible to debounce or defer the action? I know the syntax is cytoscape.js-specific, but I guess the regular possibilities of using debounce and defer apply.
I guess an easy solution would be to save a timestamp in the first event and check if endTime - startTime > threshold in the second event.
Yes, just use Lodash: cy.on('evt1 evt2 ...', _.debounce( handler ))

Using Underscore _.debounce() to trigger a single event

I have the following function that is being called from a keyPress listener on an input text field. The _.debounce() is working correctly, except instead of only firing the function 1 time after the time period, it is firing as many times as the keyPress event happened.
console.log("Pre Debounce");
var debounced = _.debounce(function() {
console.log("Field updated!");
}, 2000);
debounced();
Is there a way to limit the _.debounce function to only fire 1 time after the time period?
Possibly you are constructing the debounce function each time inside the event. If that's your case then take your debounce function outside the event response code. As far as I know the debounced function should be generated only one time and then be called multiple times.
Another thing that could go weird is when you are making an async call (ex. with an ajax autocomplete) and it takes more than your wait time for debounce then the requests could fire later making appear that debouncing is not working.
It's possible that your debounce function is taking longer to execute than the user to type. In this case, you want to make sure that you prevent double debouncing by passing in a third argument (immediate) as true.
The debounce function signature is: _.debounce(function, wait, [immediate])
So change the code to:
console.log("Pre Debounce");
var debounced = _.debounce(function() {
console.log("Field updated!");
}, 2000, true);
debounced();

Categories