onChange / onInput alternatives? - javascript

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>

Related

jQuery call animation before debounce method executes

I have a piece of code like following:
$('.cardButton').click($.debounce(1500, function () {
console.log("OK");
}));
The debounce in this case works just perfectly..
However - I need to add animation function which will replace ".cardButton" element before the debounce occurs...
Doing something like this:
$('.cardButton').click($.debounce(1500, function () {
StartAnimationLoader();
console.log("OK");
}));
// In this case - animation starts as soon as console writes out "OK" ...
Or like following:
$('.cardButton').click(function(){
StartAnimationLoader();
$.debounce(1500, function () {
console.log("OK");
})
});
// When I execute code like this - there is nothing written in the console... - thus this method doesn't works
I need to execute animation before debounce occurs ...
What am I doing wrong here?
Can someone help me out ?
Adding a 2nd (or more) event handler to the same element will fire both events (unless stopped) so you can create two actions by having two separate event handlers:
// existing debounce fire only after user stops clicking
$('.cardButton').click($.debounce... );
// additional event will fire on every click
$(".cardButton").click(function() { StartAnimationloader() });

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 ))

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

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(){ });
});

On event start calling function periodically

I have this problem:
I have real time form validation, but the inputs have autocomplete on, so when you choose a value from it, it wont trigger eny event and I cant start validating the new value.
Here is some solution which I have figured
I was thinking when input triggers onfocus event, i can start periodically (for example every one second) calling some validating functions on input, whether the value changes or not.
And on blur event I want to stop calling the function.
But I cant figure it out how to start call the function periodically...
What I have so far:
$('input[name="'+input_name+'"]').focus(function(){
checkInput(input_name);
});
function checkInput(input_name){
setInterval(doneTyping(input_name),700);
console.log(1);
}
But this only happens once, how could I do it?
Thanks.
setInterval needs an anonymous function
myInterval = setInterval(function(){doneTyping(input_name);},700);
//To clear
clearTimeout(myInterval);
do it like
var intervalID = window.setInterval(function(){ doneTyping(input_name); }, 700);
see this fiddle.

jQuery / backbone.js - delay function call

I have a #search element, which when the keyup event occurs should fire a function. This function should only fire if keyup hasn't occurred in a set amount of time (say 500 milliseconds for example). This will prevent search results from updating every letter that is pressed. The problem is that with backbone.js, I have my events in a hash and the one that is applicable looks like:
'keyup #search' : 'setSearch'
which calls the setSearch() function when the keyup event occurs. I'm not really clear on how to handle it at this point. I've tried a variety of things, but nothing can maintain the timer past the function ending.
I have something like so:
setSearch: function(event) {
var timer = window.setTimeout( function() {
// run function here
alert('fired');
}, 500);
},
rather than the alert('fired'), I'll have my own function run. I can see why this code doesn't work (a timer is set for every keyup event that occurs. But I still don't have a clear idea on what else I could try.
What you are looking for is actually a function provided to you from underscore.js (a requirement of Backbone)
setSearch: _.throttle(function() {
//Do Stuff
}, 500),
In a nutshell, this returns a new form of the anonymous function that can only be called once every 500ms. You will likely have to tweak the timing to your needs.
More Info:
http://documentcloud.github.com/underscore/#throttle
You need an instance variable in your view that stores the timer ID, then you can stop it and restart it as needed:
setSearch: function(event) {
var self = this;
if(self.timer)
clearTimeout(self.timer);
self.timer = setTimeout(function() {
alert('fired');
self.timer = null;
}, 500);
}
So, if the timer is already running, you call clearTimeout to stop it, start a new timer, and store the timer ID in self.timer (AKA this.timer). You'll also want to reset the stored timer ID in the timer's callback function or your setSearch won't do anything after its timer has fired once. And all the self business is just to capture this for use in the timer's callback function.
Preventing the updating of search results on every keyup is exactly the kind of situation that Underscore's _.debounce(function, wait) function is meant to deal with. The underscore documentation for _.debounce() states:
Creates and returns a new debounced version of the passed function which will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked. Useful for implementing behavior that should only happen after the input has stopped arriving.
Your refactored code would look as simple as:
setSearch: function(event) {
_.debounce(doSomething, 300);
},
Since you want your event handler events to be able to maintain whether or not an event has recentlyFired, you probably want to wrap your handler into a closure and maintain that status. The status should be changed to true when an event has fired, and reset to false after a delay of 500ms.
setSearch: function( ) {
var firedRecently = false;
return function(event) {
if (firedRecently) {
// it has fired recently. Do you want to do something here?
} else {
// not fired recently
firedRecently = true;
// run your function here
alert('fired');
var resetStatus = window.setTimeout( function () {
firedRecently = false;
}, 500);
}
}
}( );

Categories