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?
As James pointed out in the comments, the easiest solution to this problem is unobserving the element once it has become visible and the callback has been invoked.
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) {
callback('observer-' + entry.target.getAttribute('data-observable'));
observer.unobserve(entry.target);
}
});
}
I didn't find any viable solution to use a closure to control how often a function can be called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With