EventGenerator is reactive-style observable pattern using the new async generator language function.
Create a new generator with new EventGenerator or the shorthand eg:
// Get a test panel in the page
const testPanel = document.getElementById('test');
// Create a generator that iterates each time the click event happens
const eventIterator = eg(testPanel, 'click');
// Loop through the events
for await (const e of eventIterator) {
console.log('Clicked', e);
testPanel.textContent = `x: ${e.offsetX}, y: ${e.offsetY}`;
}This creates a loop that never stops, but you can stop listening with .stop():
// Create a generator that iterates each time the click event happens
const eventIterator = eg(testPanel, 'click');
// When a cancel button is clicked stop the iterator
const cancelButton = document.getElementById('cancel');
cancelButton.addEventListener('click', e => eventIterator.stop(), { once: true })
// Loop until cancel is clicked
for await (const e of eventIterator) {
console.log('Clicked', e);
testPanel.textContent = `x: ${e.offsetX}, y: ${e.offsetY}`;
}
// Fires once the listener is clicked
console.log('Done');
testPanel.textContent = 'Done';You can exit the loop with break and the event listener will be removed:
for await (const e of eventIterator.map(e => ({ x: e.offsetX, y: e.offsetY }))) {
console.log('Clicked', e);
testPanel.textContent = `x: ${e.x}, y: ${e.y}, ${maxClicks} clicks left`;
if(maxClicks-- <= 0)
break; // Stop looping events
}return, continue on an outer loop, or throw will have the same effect.
You can run the loop without await using .each() :
eg(testPanel, 'mousemove').
each(e => console.log(`x: ${e.offsetX}, y: ${e.offsetY}`)).
then(_ => console.log('stopped');Live demo at https://keithhenry.github.io/event-generator/, requires Chrome 63 or above.