Generating content using Ajax - scrolling to Id doesn't work
P粉208469050
P粉208469050 2024-04-04 09:29:39
0
1
570

I generate page content based on data obtained via ajax. The problem I'm having is that when I want to scroll to a certain ID, the scrolling either doesn't happen or it scrolls to the wrong location.

I've been looking at the SO Q&A but haven't found any good solutions. A lot of answers are for Angular or React, but nothing really solid for plain js.

For example, suppose the user clicks a link "About Us -> Project", "About Us" is the page, and the project is located in the id at the end of the page, which contains some content.

The problem occurs when I click on a link from a different page.

Assuming we are on the homepage, we click on the link to the About Us page, Projects section (id project). This is when the scroll doesn't work as expected. If we click on the linked item when we go to the About Us page this problem does not occur.

Since the page data is rendered in javascript, I cannot use the event listeners DOMContentLoaded or load since they fire before the content is generated (I think).

Below is my solution that doesn't work. It should check if the id is in the viewport, if not it should scroll.

I don't want to use setTimeout because it may not always work (slow internet speed, more content (images), etc.)

Any help would be greatly appreciated.

function generate(data){
   // code

    let idx = 0 //just in case, so we don't have an infinite loop
    if (window.location.href.indexOf("#") !== -1) {
        const id = window.location.href.split("#")[1];

        const element = document.getElementById(id);
        document.addEventListener('DOMContentLoaded', function () {
            console.log("loaded");
            if (element) {
                while (!isInViewport(id)) {
                    idx = idx + 1;
                    console.log(isInViewport(id))
                    scrollToElement(id);
                    if (idx === 10000){
                        break;
                    }
                };
            }
        });
    }
}

generateContent();


function scrollToElement(id) {
    const element = document.getElementById(id);
    if (element) {
        element.scrollIntoView({
            behavior: 'smooth'
        });
    }
}

function isInViewport(id) {
    const element = document.getElementById(id);
    if (element) {
        const rect = element.getBoundingClientRect();
        return (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
            rect.right <= (window.innerWidth || document.documentElement.clientWidth)
        );
    }
}

If I can provide any additional data, please let me know.

P粉208469050
P粉208469050

reply all(1)
P粉978551081

Although it's not the most elegant solution so far.

If anyone can find a better way, please let me know.

EDIT: Changed the code slightly to eliminate the issue of programmatic scrolling even after the user scrolls.

function generateContent(data){
   // code

    if (window.location.href.indexOf("#") !== -1) {
        const id = window.location.href.split("#")[1];
        const element = document.getElementById(id);
        if (element) {
            scrollToLoop(id);
        }
    }
}
generateContent();

let isUserScrolling = false;
window.addEventListener("wheel", function () {
    isUserScrolling = true;
});
window.addEventListener("touchmove", function () {
    isUserScrolling = true;
});
function scrollToLoop(id, scrl) {
    let scroll = scrl;
    const element = document.getElementById(id);

    if (element) {
        if (!isInViewport(id) && scroll && !isUserScrolling) {
            scrollToElement(id);
            setTimeout(() => {
                if (!isInViewport(id)) {
                    scrollToLoop(id, true);
                }
            }, 500);
        } else {
            setTimeout(() => {
                if (!isInViewport(id) && scroll && !isUserScrolling) {
                    scrollToLoop(id, true);
                }
            }, 500);
        }
    }
}
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template