I'm using the Intersection Observer API to track the visibility of multiple element on a web page. When an element becomes visible, a function callback()
should be executed. The restriction: For each element, the function may only be executed once.
Here is my current implementation for a web analytics project:
const elements = document.querySelectorAll('[data-observable]');
const callback = str => { console.log(str); };
const observer = new IntersectionObserver(handleIntersection);
elements.forEach(obs => {
observer.observe(obs);
});
function handleIntersection(entries, observer){
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
// Call this function only once per element, without modifying entry object
callback('observer-' + entry.target.getAttribute('data-observable'));
}
});
}
I'm struggeling to find a solution that does not modify existing elements, the IntersectionObserver or the IntersectionObserverEntries.
Usually I would use a closure to ensure that a function gets only executed once:
function once(func) {
let executed = false;
return function() {
if (!executed) {
executed = true;
return func.apply(this, arguments);
}
};
}
But in this case I have difficulties applying the function because IntersectionObserver uses a weird callback iterator logic that get's executed everytime any element changes (instead of using a event-driven model).
Any ideas, how to implement a once per element function call that does not mutate other elements or objects?