I want to write a scroll callback function that gets called after every one second when user scrolls. I tried
window.on('scroll', function(e) {
//scroll function body
});
But the problem is it gets called everytime user scrolls even one pixel. Can someone please suggest a solution.
You can write a function like this
scrollCb = function(func, later) {
var timeout;
return function() {
var context = this, args = arguments;
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
and call it like
scrollCb(function() {
//Your scroll callback handler
}, 1000);
Related
Instead of including a debounce plugin library for a very small form section of my site, I've implemented some of David Walsh's JavaScript Debounce Function in my code to allow a small wait for slower user input, however I am binding it to the input field using jQuery instead of regular DOM event listener. The code works fine but my main question here is some peer input on if this is ok to do (will it cause unforeseen issues? is there a better method?) I couldn't find another example on this scenario on stack overflow but if it has been already asked, please do point me in the right direction.
$(function() {
// debounce function by David Walsh
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
// allow .5s for slower user input before processing
var debounceCustomInput = debounce(function() {
// if both inputs valid
if ($("#left").val().length > 0 && $("#right").val().length > 0) {
// process form
myAjaxFunction();
}
}, 500);
// event binding
$(document).on("input", "#left,#right", function() {
// debounce input
debounceCustomInput();
});
});
This question already has answers here:
How to detect when mouse has stopped
(2 answers)
Closed 1 year ago.
I would like to call a function when mousemove ends.
I have an onmousemove event listener like below which fires too many times:
window.onmousemove = (e) => { console.log(e) }
I would like to reduce calling the function too often to prevent high load.
For example, call the function once when the cursor stops.
If the are any other solutions I will be glad to try them as well.
You can wrap your event callback in a debounce function. This wrapping function will only get called if you stop for 1/4 of a second after you start moving the mouse. If you start moving within 250 milliseconds after stopping, the timeout will reset and wait till you stop again.
const debounce = function(func, wait, immediate) {
let timeout;
return function() {
const
context = this,
args = arguments,
later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
},
callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const onMouseMove = (e) => {
console.log(`Stopped position: (${e.clientX}, ${e.clientY})`);
};
const debounceMouseMove = debounce(onMouseMove, 250); // 1/4 of a second
document.addEventListener('mousemove', debounceMouseMove);
There is no way of directly doing it. But you could try this:
var timeout;
element.onmousemove = function (e) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() {
// do your stuff here
}, 200);
}
It will fire if there is no event detected for 200 milliseconds.
I am working on building a search feature into my site. To do this I have a search bar which sends an AJAX request to my server each time a user types something. The server will in turn send back the items which match the search.
The only problem with this currently is that if a user types "a" and then "b" what it will send is:
a
ab
To counter this I have found setTimeout which delays when the user enters a search; however, currently it is only delaying when the strings fire (i.e. waits 0.75 seconds before sending a and then waits 0.75 seconds before sending ab).
Here's the JS:
$('#searchBox').keyup(function(e) {
var timeoutID = setTimeout(searchRequest, 750, $(e.currentTarget).val());
});
function searchRequest(str) {
if (str.length > 0) {
console.log('search request initalized | sending: ', str);
var xhttp = new XMLHttpRequest();
xhttp.open('POST', 'code to send here', true);
xhttp.send(str);
}
}
I think what you need is a debounce function.
Here's the basic JavaScript debounce function (as taken from Underscore.js):
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
You can use it to debounce click:
$('#searchBox').keyup(debounce(function(e) {
searchRequest$(e.currentTarget).val());
}, 750));
You have to clear thew timeout to make it work. Have a look on this link ;) Resetting a setTimeout
Basically, when the user added a letter, you check if you already defined a timeout. If you defined a timeout you clear it. Then you reset the timeout. Something like that
var yourTimeout;
function sendInfo(info){
if (yourTimeout != undefined)
clearTimeout(yourTimeout);
yourTimeout = setTimeout(function(){
//do something
}, 500);
}
In your case, the sendInfo function is the keyup handler, and you call searchRequest in the timeout like you already did ;)
Hope it helps
I have a wheel event setup but if you are using OS X, the event continues to fire because of the native elastic effect.
How do I prevent this elastic effect?
Here is some code...
window.addEventListener('wheel',function(){
pxCount++;
var starContainer =
document.getElementById('starContainer').style.left = '-'+50*pxCount+'px';
});
Here is the entire project http://codepen.io/www139/pen/wKbOJz
You could wrap your listener in a debounce function, the purpose of which being that a certain action is only performed once in a given time limit.
I'm a fan of this one: https://davidwalsh.name/javascript-debounce-function
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
You'd probably use it like this:
var wheelAction = debounce(function() {
pxCount++;
var starContainer =
document.getElementById('starContainer').style.left = '-'+50*pxCount+'px';
}, 250);
window.addEventListener('wheel', wheelAction);
I'm trying to debounce keystrokes in a form input on IE Mobile 6 (from what I gather, about on par with IE 3-4 in terms of support).
Due to the lack of support, I can't add event listeners after declaration (i.e., document.getElementById('elementId').addEventListener(...) doesn't work), I can only do them inline, like onkeydown="doSomething()".
Here is a jsBin.
So, with this debounce function (taken from David Walsh):
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
The recommended way to set up your event function would be like:
var doSomething = debounce(function() { ... }, 250);
However, I can't use this doSomething style function in the inline event listeners on IE Mobile 6.
So, in the markup, I've tried:
<input type="text" onkeydown="doSomething()" />
And
<input type="text" onkeydown="doSomething()()" />
And in javascript:
// return the result of debounce()
function doSomething() {
return debounce(function() { ... }, 250);
}
// just debounce()
function doSomething() {
debounce(function() { ... }, 250);
}
// return the result of the returned function of debounce, aka debounce()()
function doSomething() {
return debounce(function() { ... }, 250)();
}
I've also just tried putting the whole contents of the debounce function inside of this function, like:
function doSomething() {
var timeout, func, wait, immediate;
func = function() {
console.log('test');
};
wait = 250;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
So, long question short:
How can I write this exact statement:
var doSomething = debounce(...);
Like this:
function doSomething() {
}
You seem to have a pretty unique situation. Given that your target browser (IE Mobile 6) implements pretty old technologies (ECMAScript 3 and elements from IE 8), you won't be able to use the standard addEventListener method. Part of your problem is likely due to a mixture of the context limitations of using inline javascript along with the fact that you're programming against an old, old (1999) version of JS. Let's see how this works.
EDIT
Also make sure you're wrapping your code in some kind of document ready. I'll use jQuery to do that. That could be why your JS isn't executing.
HTML
<input type='text' id='theInput' />
<script src='yourDebounceScript.js'></script>
JS
// by the time this is executed,
// DOM elements above this script will be ready
(function() {
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
var input = document.getElementById('theInput');
input.attachEvent('keydown' function() {
// wrap your debounce function in an anonymous function
// so that you can pass arguments to the debounce as needed
debounce(function() { /* ... */ }, 250, true);
});
})();
If you can use jQuery:
// make sure the document is ready before trying to access the DOM
$(function() {
// your debounce function here...
// jQuery will handle the version compatibility for you
$('#theInput').keydown(debounce);
});