Only call function once? - javascript

So I have this javascript on a project I'm working on:
<script type="text/javascript">
document.getElementById('contact').onmouseover = function ()
{
var w = 130;
function step()
{
if (w < 250)
{
middle.style.width = (w++) + "px";
setTimeout(step, 5);
}
}
setTimeout(step, 1500);
};
</script>
I want this to run only once. After it detects a mouseover, I want it to run the function and then never run again until the page refreshes. How would I accomplish this?

I'd either use jQuery's one method or if you want to use 'plain' JavaScript you could just remove the event after the function has been triggered. Here's an example:
// Create a named function for the mouseover event
function myFunc() {
// Remove the `myFunc` function event listener once `myFunc` is run
document.getElementById('contact').removeEventListener('mouseover', myFunc, false);
var w = 130;
function step() {
if (w < 250) {
middle.style.width = (w++) + "px";
setTimeout(step, 5);
}
}
setTimeout(step, 1500);
};
// Add an event listener to run the `myFunc` function on mouseover
document.getElementById('contact').addEventListener('mouseover', myFunc, false);
Note that if you have to support IE8 (or even earlier), you need to use ...attachEvent("onmouseover", myFunc) and detachEvent("onmouseover", myFunc); instead; you can tell by checking if the element has addEventListener:
var elm = document.getElementById('contact')
if (elm.addEventListener) {
// Use addEventListener
}
else {
// Use attachEvent
}
(Perhaps hidden away in a utility function.)

All you need to do is remove the event listener from within the listener (so that it will stop listening to the event). However, in order to remove the listener, you need a reference to it, so you can't do it with a predefined listener directly attached to mouseover. Instead, use addEventListener to attach the listener, keep the returned reference and then use removeEventListener to remove the listener from within the callback.
var contact = document.getElementById('contact');
contact.addEventListener('mouseover', tehlistener);
function tehlistener() {
// yada yada do whatever
// ...
// I think it's ok to use `this` here, but since this is so specific
// its better to be specific about which listener you want removed
contact.removeEventListener('mouseover', tehlistener);
};
Here's a link to the lovely MDN article on addEventListener.

If you are interested in using JQuery, there is a nice function called "one" that may be exactly what you need.
http://api.jquery.com/one/
Edit: Adding more code to show more of the solution:
$( "#contact" ).one( "mouseover", function() {
var w = 130;
function step()
{
if (w < 250)
{
middle.style.width = (w++) + "px";
setTimeout(step, 5);
}
}
setTimeout(step, 1500);
});

You could just overwrite the event handler
<script type="text/javascript">
document.getElementById('contact').onmouseover = function() {
var w = 130;
function step() {
if (w < 250) {
middle.style.width = (w++) + "px";
setTimeout(step, 5);
}
}
setTimeout(step, 1500);
this.onmouseover = null;//overwrite event handler with a blank callback
};
</script>

You can use a once function.
function once(fn){
var called = false;
return function(){
if (called) {
return;
}
called = true;
return fn.apply(this, arguments);
}
}
Example:
something.onmouseover = once(function(){
// this will happen only once
});

Related

Removing an event listener the proper way

How do I properly remove an event listener...
function createMaze() {
var x;
for (x = 0; x < 4; x++) {
var mazeBlock = document.createElement('div');
document.body.appendChild(mazeBlock);
mazeBlock.setAttribute('class', 'blockStyle');
mazeBlock.setAttribute('id', 'mazeBlock'+x);
mazeBlock.addEventListener( 'click', function(){ eventCall(this) } );
}
}
function eventCall(t) {
alert( t.id );
t.removeEventListener(); //...know that I'm missing something here.
// Also in my code, this remove will not happen here but be initiated somewhere else in the script.
}
I did bunch of digging and the top answer there suggest to add the listener to an object for easier removal but... I'm not sure how to accomplish that
While you could save a reference to the function you call addEventListener with so you can remove it:
for (let x = 0; x < 4; x++) {
const mazeBlock = document.createElement('div');
document.body.appendChild(mazeBlock);
mazeBlock.className = 'blockStyle';
mazeBlock.id = 'mazeBlock' + x;
mazeBlock.addEventListener('click', function handler() {
mazeBlock.removeEventListener('click', handler);
eventCall(mazeBlock);
});
}
(above, eventCall is called with the <div> as the first argument)
It would be easier to make sure the function can only be called once by passing { once: true } as a third argument to addEventListener:
mazeBlock.addEventListener( 'click', eventCall, { once: true });
(above, eventCall is called with the event as the first argument - to get to the <div>, access the .target of the argument)
If you need to remove listeners for all such elements, you might consider a different approach - rather than attaching lots of listeners and then removing them all, use event delegation instead. That way, all you have to do is remove the single delegated listener:
document.body.addEventListener('click', function handler(event) {
if (!event.target.matches('.blockStyle')) return;
// A block was clicked on, remove the listener:
document.body.removeEventListener('click', handler);
// Do stuff with the clicked element:
eventCall(event.target);
});
If you're forced by weird school rules to add listeners to each element, create the listener function outside the loop, then iterate over all elements and remove the listener from each when needed:
const handler = (event) => {
document.querySelectorAll('.blockStyle').forEach((div) => {
div.removeEventListener('click', handler);
});
// do stuff with event and event.target
};
...ended up doing this:
function createMaze() {
var x;
for (x = 0; x < 4; x++) {
const mazeBlock = document.createElement('div');
document.body.appendChild(mazeBlock);
mazeBlock.className = 'blockStyle';
mazeBlock.id = 'mazeBlock' + x;
mazeBlock.addEventListener( 'click', eventCall );
}
}
function eventCall() {
alert( this.id );
}
//...this is called from another piece of the script on a separate occasion
function removeListeners() {
var blocks = document.getElementsByClassName('blockStyle');
for (var i = 0; i < blocks.length; i++) {
var block = blocks[i];
block.removeEventListener( 'click', eventCall );
}
}
#CertainPerformance Thanks for all your help! :)

Javascript ES6 addEventListener inside Class

I am learning ES6 and I don't understand why my addEventListener not working (trigger only one time) when I use a function like this :
// Trigger only one time
window.addEventListener("scroll", this.scroll() );
But when I do this :
// working !!
window.addEventListener("scroll", (e) => {
let top = window.pageYOffset;
console.log(top + " vs " + this.offsetTop)
if (top >= this.offsetTop) {
this.el.classList.add('is-sticky');
} else {
this.el.classList.remove('is-sticky');
}
});
The full code can be find here : https://codepen.io/paallaire/pen/GQLzmg/?editors=0010#0
The statement:
window.addEventListener("scroll", this.scroll() );
Binds to the event the result of this.scroll(), which is a function call. Such invocation returns undefined, because the scroll method has no return statement:
scroll() {
let top = window.pageYOffset;
console.log(top + " vs " + this.offsetTop);
if (top >= this.offsetTop) {
this.el.classList.add('is-sticky');
} else {
this.el.classList.remove('is-sticky');
}
}
Correct way
Do NOT use:
window.addEventListener("scroll", this.scroll);
The code above will bind the this to window when the event triggers.
The CORRECT way to use is really:
window.addEventListener("scroll", (e) => {
this.scroll();
});
Or
window.addEventListener("scroll", this.scroll.bind(this));
Which, when the event is triggered, will have the code inside this.scroll have the this point to the current class (Sticky) instance.
Removing the event listener
To remove the event, call window.removeEventListener, but there's a caveat: removeEventListener must be called with the exact same argument used in addEventListener to remove the listener. In other words, to be able to remove you will have to do:
// save the function that will be bound to the event, so you can remove it later
this.scrollBoundFunction = this.scroll.bind(this);
window.addEventListener("scroll", this.scrollBoundFunction);
// and later
window.removeEventListener("scroll", this.scrollBoundFunction);

Fire resize event once not based on timing

Is it possible to avoid twice firing events by browsers, but not based on timing (in case your resize event execution lasts long that solution is bad)
window.blockResize = false;
$(window).resize(function() {
if (window.blockResize) return;
//do stuff
window.blockResize = true;
setTimeout(function(){window.blockResize = false},200);
});
Ok, it's still based on timers, but It works in my case now.
You can use setTimeout() and clearTimeout() in conjunction with jQuery.data:
$(window).resize(function() {
clearTimeout($.data(this, 'resizeTimer'));
$.data(this, 'resizeTimer', setTimeout(function() {
//do something
alert("Haven't resized in 200ms!");
}, 200));
});
Update
I wrote an extension to enhance jQuery's default on (& bind)-event-handler. It attaches an event handler function for one or more events to the selected elements if the event was not triggered for a given interval. This is useful if you want to fire a callback only after a delay, like the resize event, or else.
https://github.com/yckart/jquery.unevent.js
;(function ($) {
var methods = { on: $.fn.on, bind: $.fn.bind };
$.each(methods, function(k){
$.fn[k] = function () {
var args = [].slice.call(arguments),
delay = args.pop(),
fn = args.pop(),
timer;
args.push(function () {
var self = this,
arg = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
fn.apply(self, [].slice.call(arg));
}, delay);
});
return methods[k].apply(this, isNaN(delay) ? arguments : args);
};
});
}(jQuery));
Use it like any other on or bind-event handler, except that you can pass an extra parameter as a last:
$(window).on('resize', function(e) {
console.log(e.type + '-event was 200ms not triggered');
}, 200);
http://jsfiddle.net/ARTsinn/EqqHx/

How do I stop this event listener from automatically firing

I've got this self-executing function, which adds event listeners to a series of links. But the event listeners are automatically firing when the page loads, as opposed to onmouseover/out. Have I got the syntax wrong? How do I stop them autofiring?
;(function(){
var menuLink = $('.navItem');
var menuItem = $('.menuLinks');
for (a = 0; a <= 5; ++a) {
menuLink[a].addEventListener('onmouseover', linkChanger(), true);
menuLink[a].addEventListener('onmouseout', linkChanger(), true);
}
function linkChanger(event){
if (menuItem[a].style.color == "white") {
console.log("This is white")
menuItem[a].style.color = "black";
}
else {
console.log("This is black");
menuItem[a].style.color = "white";
}
}
})()
menuLink[a].addEventListener('onmouseover', linkChanger, true);
menuLink[a].addEventListener('onmouseout', linkChanger, true);
When you write linkChanger(), it is executing the function and giving the result to the Listener. Either wrap it with function() { linkChanger(); } or replace with linkChanger. The first option allows you to pass arguments and run other functions too.

How to wait for the 'end' of 'resize' event and only then perform an action?

So I currently use something like:
$(window).resize(function(){resizedw();});
But this gets called many times while resizing process goes on. Is it possible to catch an event when it ends?
You can use setTimeout() and clearTimeout()
function resizedw(){
// Haven't resized in 100ms!
}
var doit;
window.onresize = function(){
clearTimeout(doit);
doit = setTimeout(resizedw, 100);
};
Code example on jsfiddle.
I had luck with the following recommendation: http://forum.jquery.com/topic/the-resizeend-event
Here's the code so you don't have to dig through his post's link & source:
var rtime;
var timeout = false;
var delta = 200;
$(window).resize(function() {
rtime = new Date();
if (timeout === false) {
timeout = true;
setTimeout(resizeend, delta);
}
});
function resizeend() {
if (new Date() - rtime < delta) {
setTimeout(resizeend, delta);
} else {
timeout = false;
alert('Done resizing');
}
}
Thanks sime.vidas for the code!
This is the code that I write according to #Mark Coleman answer:
$(window).resize(function() {
clearTimeout(window.resizedFinished);
window.resizedFinished = setTimeout(function(){
console.log('Resized finished.');
}, 250);
});
Thanks Mark!
Internet Explorer provides a resizeEnd event. Other browsers will trigger the resize event many times while you're resizing.
There are other great answers here that show how to use setTimeout and the .throttle, .debounce methods from lodash and underscore, so I will mention Ben Alman's throttle-debounce jQuery plugin which accomplishes what you're after.
Suppose you have this function that you want to trigger after a resize:
function onResize() {
console.log("Resize just happened!");
};
Throttle Example
In the following example, onResize() will only be called once every 250 milliseconds during a window resize.
$(window).resize( $.throttle( 250, onResize) );
Debounce Example
In the following example, onResize() will only be called once at the end of a window resizing action. This achieves the same result that #Mark presents in his answer.
$(window).resize( $.debounce( 250, onResize) );
There is an elegant solution using the Underscore.js So, if you are using it in your project you can do the following -
$( window ).resize( _.debounce( resizedw, 500 ) );
This should be enough :) But, If you are interested to read more on that, you can check my blog post - http://rifatnabi.com/post/detect-end-of-jquery-resize-event-using-underscore-debounce(deadlink)
There is a much simpler method to execute a function at the end of the resize than calculate the delta time between two calls, simply do it like this :
var resizeId;
$(window).resize(function() {
clearTimeout(resizeId);
resizeId = setTimeout(resizedEnded, 500);
});
function resizedEnded(){
...
}
And the equivalent for Angular2 :
private resizeId;
#HostListener('window:resize', ['$event'])
onResized(event: Event) {
clearTimeout(this.resizeId);
this.resizeId = setTimeout(() => {
// Your callback method here.
}, 500);
}
For the angular method, use the () => { } notation in the setTimeout to preserve the scope, otherwise you will not be able to make any function calls or use this.
One solution is extend jQuery with a function, e.g.: resized
$.fn.resized = function (callback, timeout) {
$(this).resize(function () {
var $this = $(this);
if ($this.data('resizeTimeout')) {
clearTimeout($this.data('resizeTimeout'));
}
$this.data('resizeTimeout', setTimeout(callback, timeout));
});
};
Sample usage:
$(window).resized(myHandler, 300);
You can store a reference id to any setInterval or setTimeout. Like this:
var loop = setInterval(func, 30);
// some time later clear the interval
clearInterval(loop);
To do this without a "global" variable you can add a local variable to the function itself. Ex:
$(window).resize(function() {
clearTimeout(this.id);
this.id = setTimeout(doneResizing, 500);
});
function doneResizing(){
$("body").append("<br/>done!");
}
You can use setTimeout() and clearTimeout() in conjunction with jQuery.data:
$(window).resize(function() {
clearTimeout($.data(this, 'resizeTimer'));
$.data(this, 'resizeTimer', setTimeout(function() {
//do something
alert("Haven't resized in 200ms!");
}, 200));
});
Update
I wrote an extension to enhance jQuery's default on (& bind)-event-handler. It attaches an event handler function for one or more events to the selected elements if the event was not triggered for a given interval. This is useful if you want to fire a callback only after a delay, like the resize event, or else.
https://github.com/yckart/jquery.unevent.js
;(function ($) {
var methods = { on: $.fn.on, bind: $.fn.bind };
$.each(methods, function(k){
$.fn[k] = function () {
var args = [].slice.call(arguments),
delay = args.pop(),
fn = args.pop(),
timer;
args.push(function () {
var self = this,
arg = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
fn.apply(self, [].slice.call(arg));
}, delay);
});
return methods[k].apply(this, isNaN(delay) ? arguments : args);
};
});
}(jQuery));
Use it like any other on or bind-event handler, except that you can pass an extra parameter as a last:
$(window).on('resize', function(e) {
console.log(e.type + '-event was 200ms not triggered');
}, 200);
http://jsfiddle.net/ARTsinn/EqqHx/
Mark Coleman's answer is certainly far better than the selected answer, but if you want to avoid the global variable for the timeout ID (the doit variable in Mark's answer), you could do one of the following:
(1) Use a an immediately invoked function expression (IIFE) to create a closure.
$(window).resize((function() { // This function is immediately invoked
// and returns the closure function.
var timeoutId;
return function() {
clearTimeout(timeoutId);
timeoutId = setTimeout(function() {
timeoutId = null; // You could leave this line out.
// Code to execute on resize goes here.
}, 100);
};
})());
(2) Use a property of the event handler function.
$(window).resize(function() {
var thisFunction = arguments.callee;
clearTimeout(thisFunction.timeoutId);
thisFunction.timeoutId = setTimeout(function() {
thisFunction.timeoutId = null; // You could leave this line out.
// Code to execute on resize goes here.
}, 100);
});
This is what I use for delaying repeated actions, it can be called in multiple places in your code:
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);
};
};
Usage:
$(window).resize(function () {
debounce(function() {
//...
}, 500);
});
ResizeStart and ResizeEnd events for window
http://jsfiddle.net/04fLy8t4/
I implemented a function which trigs two events on the user DOM element:
resizestart
resizeend
Code:
var resizeEventsTrigger = (function () {
function triggerResizeStart($el) {
$el.trigger('resizestart');
isStart = !isStart;
}
function triggerResizeEnd($el) {
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
$el.trigger('resizeend');
isStart = !isStart;
}, delay);
}
var isStart = true;
var delay = 200;
var timeoutId;
return function ($el) {
isStart ? triggerResizeStart($el) : triggerResizeEnd($el);
};
})();
$("#my").on('resizestart', function () {
console.log('resize start');
});
$("#my").on('resizeend', function () {
console.log('resize end');
});
window.onresize = function () {
resizeEventsTrigger( $("#my") );
};
This is a modification to Dolan's code above, I've added a feature which checks the window size at the start of the resize and compares it to the size at the end of the resize, if size is either bigger or smaller than the margin (eg. 1000) then it reloads.
var rtime = new Date(1, 1, 2000, 12,00,00);
var timeout = false;
var delta = 200;
var windowsize = $window.width();
var windowsizeInitial = $window.width();
$(window).on('resize',function() {
windowsize = $window.width();
rtime = new Date();
if (timeout === false) {
timeout = true;
setTimeout(resizeend, delta);
}
});
function resizeend() {
if (new Date() - rtime < delta) {
setTimeout(resizeend, delta);
return false;
} else {
if (windowsizeInitial > 1000 && windowsize > 1000 ) {
setTimeout(resizeend, delta);
return false;
}
if (windowsizeInitial < 1001 && windowsize < 1001 ) {
setTimeout(resizeend, delta);
return false;
} else {
timeout = false;
location.reload();
}
}
windowsizeInitial = $window.width();
return false;
}
Here is VERY simple script to trigger both a 'resizestart' and 'resizeend' event on the window object.
There is no need to muck around with dates and times.
The d variable represents the number of milliseconds between resize events before triggering the resize end event, you can play with this to change how sensitive the end event is.
To listen to these events all you need to do is:
resizestart: $(window).on('resizestart', function(event){console.log('Resize Start!');});
resizeend:
$(window).on('resizeend', function(event){console.log('Resize End!');});
(function ($) {
var d = 250, t = null, e = null, h, r = false;
h = function () {
r = false;
$(window).trigger('resizeend', e);
};
$(window).on('resize', function (event) {
e = event || e;
clearTimeout(t);
if (!r) {
$(window).trigger('resizestart', e);
r = true;
}
t = setTimeout(h, d);
});
}(jQuery));
i wrote a litte wrapper function on my own...
onResize = function(fn) {
if(!fn || typeof fn != 'function')
return 0;
var args = Array.prototype.slice.call(arguments, 1);
onResize.fnArr = onResize.fnArr || [];
onResize.fnArr.push([fn, args]);
onResize.loop = function() {
$.each(onResize.fnArr, function(index, fnWithArgs) {
fnWithArgs[0].apply(undefined, fnWithArgs[1]);
});
};
$(window).on('resize', function(e) {
window.clearTimeout(onResize.timeout);
onResize.timeout = window.setTimeout("onResize.loop();", 300);
});
};
Here is the usage:
var testFn = function(arg1, arg2) {
console.log('[testFn] arg1: '+arg1);
console.log('[testFn] arg2: '+arg2);
};
// document ready
$(function() {
onResize(testFn, 'argument1', 'argument2');
});
(function(){
var special = jQuery.event.special,
uid1 = 'D' + (+new Date()),
uid2 = 'D' + (+new Date() + 1);
special.resizestart = {
setup: function() {
var timer,
handler = function(evt) {
var _self = this,
_args = arguments;
if (timer) {
clearTimeout(timer);
} else {
evt.type = 'resizestart';
jQuery.event.handle.apply(_self, _args);
}
timer = setTimeout( function(){
timer = null;
}, special.resizestop.latency);
};
jQuery(this).bind('resize', handler).data(uid1, handler);
},
teardown: function(){
jQuery(this).unbind( 'resize', jQuery(this).data(uid1) );
}
};
special.resizestop = {
latency: 200,
setup: function() {
var timer,
handler = function(evt) {
var _self = this,
_args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout( function(){
timer = null;
evt.type = 'resizestop';
jQuery.event.handle.apply(_self, _args);
}, special.resizestop.latency);
};
jQuery(this).bind('resize', handler).data(uid2, handler);
},
teardown: function() {
jQuery(this).unbind( 'resize', jQuery(this).data(uid2) );
}
};
})();
$(window).bind('resizestop',function(){
//...
});
Well, as far as the window manager is concerned, each resize event is its own message, with a distinct beginning and end, so technically, every time the window is resized, it is the end.
Having said that, maybe you want to set a delay to your continuation? Here's an example.
var t = -1;
function doResize()
{
document.write('resize');
}
$(document).ready(function(){
$(window).resize(function(){
clearTimeout(t);
t = setTimeout(doResize, 1000);
});
});
I guess my case might be different from some others but I had a problem only with orientation change on iOS but wanted the resize event to run immediately. I used the ScreenOrientation API:
screen.orientation.addEventListener('change', (e) => {});
I took a slightly different tack and relied on mouseUp as the end of the resize event. trackSize is called on documentReady and the initial value of wide is set then, too.
var THRESHOLD = 784;
var TALL = 125, SHORT = 50;
var wide = (window.document.body.clientWidth >= THRESHOLD );
function trackSize() {
if( !wide ) {
setHeight( TALL );
} else {
setHeight( SHORT );
}
parent.window.addEventListener('resize', onResize);
}
function onResize(e) {
parent.window.removeEventListener('resize', onResize);
parent.window.addEventListener('mouseup', onMouseUp) ;
}
function onMouseUp(e) {
parent.window.removeEventListener('mouseup', onMouseUp);
wide = (window.document.body.clientWidth >= THRESHOLD);
trackSize();
}
After having set our window's initial height, we begin listening for a resize event. When it starts, we stop listening and start listening for the mouseUp event. Thus, we know that mouseUp will end the resizing. In mouseUp, we stop listening and set a toggle based on the window's width, then loop back to trackSize.
trackSize starts by setting the window's height based on the toggle -- if below the threshold, we increase height (because Bootstrap columns stack at small widths), otherwise set to standard. And then we listen again for the next resize event.
CAVEAT: This solution doesn't really work for resizing instantly using the maximize or restore window buttons. Maybe adding a test like isMouseDown and bypassing the mouse listener would suffice - I haven't yet tested that.
since the selected answer didn't actually work .. and if you're not using jquery here is a simple throttle function with an example of how to use it with window resizing
function throttle(end,delta) {
var base = this;
base.wait = false;
base.delta = 200;
base.end = end;
base.trigger = function(context) {
//only allow if we aren't waiting for another event
if ( !base.wait ) {
//signal we already have a resize event
base.wait = true;
//if we are trying to resize and we
setTimeout(function() {
//call the end function
if(base.end) base.end.call(context);
//reset the resize trigger
base.wait = false;
}, base.delta);
}
}
};
var windowResize = new throttle(function() {console.log('throttle resize');},200);
window.onresize = function(event) {
windowResize.trigger();
}
this worked for me as I did not want to use any plugins.
$(window).resize(function() {
var originalWindowSize = 0;
var currentWidth = 0;
var setFn = function () {
originalWindowSize = $(window).width();
};
var checkFn = function () {
setTimeout(function () {
currentWidth = $(window).width();
if (currentWidth === originalWindowSize) {
console.info("same? = yes")
// execute code
} else {
console.info("same? = no");
// do nothing
}
}, 500)
};
setFn();
checkFn();
});
On window re-size invoke "setFn" which gets width of window and save as "originalWindowSize". Then invoke "checkFn" which after 500ms (or your preference) gets the current window size, and compares the original to the current, if they are not the same, then the window is still being re-sized. Don't forget to remove console messages in production, and (optional) can make "setFn" self executing.
var resizeTimer;
$( window ).resize(function() {
if(resizeTimer){
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(function() {
//your code here
resizeTimer = null;
}, 200);
});
This worked for what I was trying to do in chrome. This won't fire the callback until 200ms after last resize event.
UPDATE!
Better alternative also created by me is here:
https://stackoverflow.com/a/23692008/2829600
(supports "delete functions")
ORIGINAL POST:
I wrote this simple function for handling delay in execution, useful inside jQuery .scroll() and .resize() So callback_f will run only once for specific id string.
function delay_exec( id, wait_time, callback_f ){
// IF WAIT TIME IS NOT ENTERED IN FUNCTION CALL,
// SET IT TO DEFAULT VALUE: 0.5 SECOND
if( typeof wait_time === "undefined" )
wait_time = 500;
// CREATE GLOBAL ARRAY(IF ITS NOT ALREADY CREATED)
// WHERE WE STORE CURRENTLY RUNNING setTimeout() FUNCTION FOR THIS ID
if( typeof window['delay_exec'] === "undefined" )
window['delay_exec'] = [];
// RESET CURRENTLY RUNNING setTimeout() FUNCTION FOR THIS ID,
// SO IN THAT WAY WE ARE SURE THAT callback_f WILL RUN ONLY ONE TIME
// ( ON LATEST CALL ON delay_exec FUNCTION WITH SAME ID )
if( typeof window['delay_exec'][id] !== "undefined" )
clearTimeout( window['delay_exec'][id] );
// SET NEW TIMEOUT AND EXECUTE callback_f WHEN wait_time EXPIRES,
// BUT ONLY IF THERE ISNT ANY MORE FUTURE CALLS ( IN wait_time PERIOD )
// TO delay_exec FUNCTION WITH SAME ID AS CURRENT ONE
window['delay_exec'][id] = setTimeout( callback_f , wait_time );
}
// USAGE
jQuery(window).resize(function() {
delay_exec('test1', 1000, function(){
console.log('1st call to delay "test1" successfully executed!');
});
delay_exec('test1', 1000, function(){
console.log('2nd call to delay "test1" successfully executed!');
});
delay_exec('test1', 1000, function(){
console.log('3rd call to delay "test1" successfully executed!');
});
delay_exec('test2', 1000, function(){
console.log('1st call to delay "test2" successfully executed!');
});
delay_exec('test3', 1000, function(){
console.log('1st call to delay "test3" successfully executed!');
});
});
/* RESULT
3rd call to delay "test1" successfully executed!
1st call to delay "test2" successfully executed!
1st call to delay "test3" successfully executed!
*/
var flag=true;
var timeloop;
$(window).resize(function(){
rtime=new Date();
if(flag){
flag=false;
timeloop=setInterval(function(){
if(new Date()-rtime>100)
myAction();
},100);
}
})
function myAction(){
clearInterval(timeloop);
flag=true;
//any other code...
}
I don't know is my code work for other but it's really do a great job for me. I got this idea by analyzing Dolan Antenucci code because his version is not work for me and I really hope it'll be helpful to someone.
var tranStatus = false;
$(window).resizeend(200, function(){
$(".cat-name, .category").removeAttr("style");
//clearTimeout(homeResize);
$("*").one("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend",function(event) {
tranStatus = true;
});
processResize();
});
function processResize(){
homeResize = setInterval(function(){
if(tranStatus===false){
console.log("not yet");
$("*").one("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend",function(event) {
tranStatus = true;
});
}else{
text_height();
clearInterval(homeResize);
}
},200);
}
I wrote a function that passes a function when wrapped in any resize event. It uses an interval so that the resize even isn't constantly creating timeout events. This allows it to perform independently of the resize event other than a log entry that should be removed in production.
https://github.com/UniWrighte/resizeOnEnd/blob/master/resizeOnEnd.js
$(window).resize(function(){
//call to resizeEnd function to execute function on resize end.
//can be passed as function name or anonymous function
resizeEnd(function(){
});
});
//global variables for reference outside of interval
var interval = null;
var width = $(window).width();
var numi = 0; //can be removed in production
function resizeEnd(functionCall){
//check for null interval
if(!interval){
//set to new interval
interval = setInterval(function(){
//get width to compare
width2 = $(window).width();
//if stored width equals new width
if(width === width2){
//clear interval, set to null, and call passed function
clearInterval(interval);
interval = null; //precaution
functionCall();
}
//set width to compare on next interval after half a second
width = $(window).width();
}, 500);
}else{
//logging that should be removed in production
console.log("function call " + numi++ + " and inteval set skipped");
}
}

Categories

Resources