Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

andyandy's avatar

[JS] infinite page scroll with Intersection Observer

I'm making infinite scroll. When I scroll down to "#infinite-scroll-trigger-reached" it will remove this DIV. Insert via AJAX 10 more posts. And put new "#infinite-scroll-trigger-reached" DIV after them.

I have Intersection Observer, when "#infinite-scroll-trigger-reached" DIV gets into viewport it will trigger it.

However it will trigger only first time. After removing/adding again of "#infinite-scroll-trigger-reached" DIV it will new fire again.

I tried unobserve/observe it again and lot of other things, but I can't make it work for the second time.

/** INFINITE SCROLL OBSERVER **/
const target = document.querySelector('#infinite-scroll-trigger-reached');
function handleIntersection(entries) {
    entries.map((entry) => {
        if (entry.isIntersecting && allowChanges) {
            allowChanges = false;
            infiniteScroll();
            console.log('observed');
        }
    });
}
const observer = new IntersectionObserver(handleIntersection);
observer.observe(target);

0 likes
3 replies
rodrigo.pedra's avatar
Level 56

document.querySelector(...) grabs a reference to an existing DOM node from the HTML document's DOM that matches the argument selector in the moment it is called.

It doesn't keep looking for new nodes that matches the selector.

A DOM node is a structure in memory. New nodes with the same selector won't be automatically bound to the variable you previously saved a reference for.

When I scroll down to "#infinite-scroll-trigger-reached" it will remove this DIV.

The observer is observing to this specific DIV node you just removed. You shouldn't expect any new events as your removed the observing target from the DOM.

put new "#infinite-scroll-trigger-reached" DIV after them.

The new DIV is a entirely new data-strucuture in memory, a brand new node in your HTML document, that happens to share the same ID as the one you previously removed. Other than that common trait it is a different object/value that you are still not referencing in JavaScript code. It won't be observed by the current observer instance you have until you call .observe(...) on it.

Why not add the new resultset nodes before the "#infinite-scroll-trigger-reached" DIV you already have?

If that is not feasible (your backend could be returning a HTML fragment that includes a new "#infinite-scroll-trigger-reached" DIV), you have to unobserve the old "#infinite-scroll-trigger-reached" DIV , and manually query the DOM after the new "#infinite-scroll-trigger-reached" DIV is inserted and observe that.

Note also the until you call .unobserve(...) on the removed "#infinite-scroll-trigger-reached" DIV , that DOM node will still be in browser memory which can lead to a memory consumption increase over time (memory leak).

Hope it makes things clearer.

1 like

Please or to participate in this conversation.