Demo:
Open your console or resize this window
Let's make some simple example functions for this demo:
After page load, if this window is resized, let's make a UI update and log some messages to the console:
UI The page has not been resized.
Javascript
function updateDemoUI()
{
const badge = document.getElementById('demoTarget-UI');
const text = document.getElementById('demoTarget-text');
badge.classList.replace('badge-primary', 'badge-success');
text.innerText = 'The UI has been updated';
}
function test1() { console.log('performed test function 1'); }
function test2() { console.log('performed test function 2'); }
function test3() { console.log('performed test function 3'); }
This demo runs each function once. The WindowResizeObserver can be continuous and/or allow functions to run again after a timeout.
How to:
Javascript
Get a copy of WindowResizeObserver.js
Javascript
class WindowResizeObserver
{
/**
*
* @param {Boolean} [once] Perform all actions once. Default false.
* @param {Number} [queueDelay] Milliseconds before enqueueing again. Default 0 - does not requeue.
*
*/
constructor(once = false, queueDelay = 0)
{
this.actions = [];
this.once = once;
this.queueDelay = queueDelay;
this.enqueueActions();
}
/**
*
* Assign 'resize' listener to window that will run the main function
*
* @return {undefined}
*/
enqueueActions()
{
window.addEventListener('resize', (event) =>
{
this.performActions();
}, { once: this.once });
}
/**
* Change action enqueue delay or turn it off by setting it to 0
*
* @param {Number} queueDelay Milliseconds delay before enqueueing action list again.
*
* @return {undefined}
*/
resetQueueDelay(queueDelay)
{
if (queueDelay > 0) { this.enqueueActions(); }
else { this.queueDelay = 0; }
}
/**
*
* main: do each action then put the actions back in queue
*
* @return {undefined}
*
*/
performActions()
{
this.actions.forEach( (action) => { action(); } );
if (this.queueDelay)
{
setTimeout(() => { this.enqueueActions(); }, this.queueDelay);
}
}
/**
* Get the actions list
*
* @param {Boolean} [asShallowCopy] Optional. Default false.
*
* @return {*[]|[]}
*/
getActions(asShallowCopy = false)
{
// return this.actions;
return (asShallowCopy) ? [...this.actions] : this.actions;
}
/**
* Get length of list of actions
*
* @return {Number}
*/
getActionsLength() { return this.actions.length; }
/**
* Get an action at an index
*
* @param {Number} pos
*
* @return {Function}
*/
getActionAt(pos) { return this.actions[pos]; }
/**
* Get the index of an action by its name
*
* @param {Function} action
*
* @return {number}
*/
getIndexOf(action)
{
const pos = this.actions.indexOf(action);
if(pos >= 0) { return pos; }
else { console.error(`No index found for ${action.name}.`); }
}
/**
* Push to actions array
*
* @param {Function} action
*
* @return {undefined}
*/
append(action) { this.actions.push(action); }
/**
* Unshift to actions array
*
* @param {Function} action
*
* @return {undefined}
*/
prepend(action) { this.actions.unshift(action); }
/**
* Replace an action at an index
*
* @param {Number} pos
* @param {Function} newAction
*
* @return {undefined}
*/
replaceActionAt(pos, newAction) { this.actions[pos] = newAction; }
/**
* Replace an action by its name
*
* @param {Function} action
* @param {Function} newAction
*
* @return {undefined}
*/
replaceAction(action, newAction)
{
const pos = this.getIndexOf(action);
if ( pos >= 0) { this.replaceActionAt(pos, newAction); }
else { console.error(`Unable to swap ${action} for ${newAction}. No index found for ${action}.`); }
}
/**
* Swap positions of two actions
*
* @param {Number} posA Index of an action to be swapped
* @param {Number} posB Index of an action to be swapped
*
* @return {undefined}
*/
swapActionsAt(posA, posB)
{
if (this.actions[a] && this.actions[b])
{
[this.actions[a], this.actions[b]] = [this.actions[b], this.actions[a]];
}
else
{
if (this.actions[a] === undefined && this.actions[b] === undefined)
{
console.error(`Attempting to swap with undefined indices: [${a}] and [${b}].`)
}
if(this.actions[a] === undefined && this.actions[b] !== undefined)
{
console.error(`Attempting to swap [${b}] with an undefined index [${a}].`)
}
if(this.actions[b] === undefined && this.actions[a] !== undefined)
{
console.error(`Attempting to swap [${a}] with an undefined index [${b}].`)
}
}
}
/**
* Get index positions of functions a and b and passes them to swapActionsAt()
*
* @param {Function} actionA A function to swap
* @param {Function} actionB A function to swap
*/
swapActions(actionA, actionB)
{
const posA = this.getIndexOf(a);
const posB = this.getIndexOf(b);
this.swapActionsAt(posA, posB);
}
/**
* Remove a function from list of actions by index
*
* @param {number} pos
*
* @return {undefined}
*/
removeActionAt(pos) { this.actions.splice(pos, 1); }
/**
* Remove a function from list of actions by name
*
* @param {Function} action
*
* @return {undefined}
*/
removeAction(action) { this.removeActionAt( this.getIndexOf(action) ); }
/**
* Reset the action queue to an empty array
*
* @return undefined
*/
clearQueue()
{
this.actions = [];
}
/**
* Log the list of actions
*
* @param {Boolean} asShallowCopy Default false
*
* @return {undefined}
*/
dumpActions(asShallowCopy = false)
{
console.log(this.getActions(asShallowCopy));
}
/**
* Log the action list's indices and (functions or function names)
*
* @param {boolean} asShallowCopy Default false
* @param {boolean} namesOnly Default false
*
* @return {undefined}
*/
dumpValues(asShallowCopy = false, namesOnly = false)
{
const current = this.getActions(asShallowCopy);
if (namesOnly) { for (const i in current) { console.log(`${i}: ${current[i].name}`); } }
else { for (const i in current) { console.log(`${i}: ${current[i]}`); } }
}
/**
* Log the action list formatted as a string
*
* @param {Boolean} asShallowCopy Default false
*
* @return {undefined}
*/
dumpActionNames(asShallowCopy = false)
{
const current = this.getActions(asShallowCopy);
const names = this.actionNamesToString(current);
console.log(names);
}
/**
* Build a string from the names of the functions in the action list
*
* @param {Array} actionsList
* @return {String}
*/
actionNamesToString(actionsList)
{
// get each function name
const names = [];
for (const action of actionsList) { names.push(action.name) }
// return them as a string
return '[' + names.join(', ') + ']';
}
}
Create an instance of the WindowResizeObserver class:
Javascript
<script src="path/to/WindowResizeObserver.js"></script>
<script>
const ResizeObserver = new WindowResizeObserver(true);
</script>
Populate the action queue using append()
:
Javascript
ResizeObserver.append(updateDemoUI);
ResizeObserver.append(test1);
ResizeObserver.append(test2);
ResizeObserver.append(test3);
Using these demo functions, when you resize the window, your console output should be:
performed test function 1
performed test function 2
performed test function 3
More:
What else can you do with WindowResizeObserver.js
?
Observe your action queue:
- Get action queue as a string with
dumpActionNames()
. Pass intrue
to get a shallow copy. - Log the action queue to the console with
dumpActions()
. Pass intrue
to get a shallow copy. - Log each index and action definition in the queue with
dumpValues()
.- Pass in
true
as the first parameter to get a shallow copy. - If you pass in
true
as the second parameter, it will log function names instead of definitions.
- Pass in
Manage your action queue:
- Add a function to the beginning of the queue with
prepend(action)
- Add a function to the end of the queue with
append(action)
- Replace an action by name or index position
replaceAction(action, newAction)
replaceActionAt(pos, newAction)
- Swap the position of 2 actions by name or index position
swapActions(actionA, actionB)
swapActionsAt(posA, posB)
- Remove all actions from the queue with
clearQueue()
- Remove an action by name or index position
removeAction(action)
removeActionAt(pos)
- Enable, disable, or adjust the re-queue delay with
resetQueueDelay(delay)
where 'delay' is some number of milliseconds.- Pass in
0
to disable. Negative numbers will be reset to 0. - Use a number greater than 0 to enable or adjust the re-queue delay.
- Pass in
- Trigger the queue with
performActions()
Query your action queue:
- Get the action queue with
getActions()
. Pass intrue
to get a shallow copy. - Get the number of actions in queue with
getActionsLength()
- Get the position of an action, by name, with
getIndexOf(action)
- Get the action at an index with
getActionAt(pos)
Options:
Running the queue more than once.
Decide how often your functions need to run.
There are 4 ways you can use the WindowResizeObserver. Two of them are "safe". One can be questionable, and one can be outright madness. The class has 2 optional parameters for construction. By default, they are both false. Using the class this way can quickly lead to your functions being run dozens, hundreds, thousands... of times. Chances are that's not what you want to do.
You should initialize new instances by passing in 'true' as the first argument. This will make your functions run once. The page will have to be reloaded for them to run again.
You can also pass in a number (of milliseconds) as the second argument. Doing so will trigger a timeout before re-queueing your action list again. For example:
const ResizeObserver = new WindowResizeObserver(true, 1000);
That will create an instance that runs once, then waits one second before allowing actions to run again.
Project Galleries
Tool
Color Average
Blend two colors to get their linear and logarithmic mid-point.
Tool
Multi Tab Opener
Like bookmarks on steroids: time released links with options and storage.
App
Jitter Bug
Simulated page traffic and product sales for marketing.
App
Shopping Cart
Originally made for use on Unbounce with Checkout Champ.
Tool
Public Library
A nifty little reading lens for classic novels using the Spritz SDK.
Collapse & Reveal
Animated Component
Slide a content block's height up or down.
Move Elements
Animated Component
Change or restore the location of a content block.
Code Snippet
Animated Component
The source code for this website's custom code snippet component.
Tabbed Panes
Animated Component
Nav tabs with content panels that fade in and out.
Window Resize Observer
Utility
Manage and perform a list of actions when the browser is resized.
Console Formatter
Utility
Opinionated extensions for console messages.
Fuzzy Scroll
Utility
Improved scroll-to behavior.
Cube Node
Have fun building structures by joining nodes with chopsticks
Laptop Stand
Use 2 to hold a thin laptop upright. Great with a wireless keyboard
Little Buggy
A toy for kids. Requires 9V battery, small gray motor, and bouncy balls for feet
MicroSD Card Ring
Holds 16 MicroSD cards. Doubles as a paper weight