Infinite Scroll (loading data fom server connect) Similar to Lazy Load

I would like this feature, please Wappler team make it happen :slightly_smiling_face:

1 Like

Just saw this is one of the most voted requests.

Infinite scroll only makes sense in very few scenarios. Mobile and timeline pages with no footer(like discourse for instance).

If not implemented correctly it can become a UX nightmare. There are stories out there of people that have been chasing a specific footer for years.

I prefer to use a “Load More” link/button as it gives the final user sense of control over the UI.

But it would be nice for certain scenarios indeed.

3 Likes

Tabulator has this functionality – ajax progressive.

1 Like

Bumping this request!

Bumping again. Essential for mobile apps. :wink:

1 Like

Be sure to vote here as well ......

1 Like

Bumping again

There is already an infinite scroll component in the extensions library here:

It works perfectly.

The full list of extensions is here:

Unfortunately Ken’s extension does not work in mobile projects due to limitations in custom components in mobile projects.

Bump

Bump - 86 votes up to now and we're still no closer to having this implemented.

90 votes!

Hi Wappler Team,

Hope you’re all doing great!

As we continue building more dynamic and interactive applications, we’ve noticed that features like infinite scroll have become almost essential — especially for things like feeds, chats, and content-heavy interfaces.

Currently, implementing this in Wappler requires quite a bit of workaround, since there’s no native support yet. We’d love to see infinite scroll become a built-in feature! Not only would it simplify development, but it could also give Wappler an edge in a market that’s increasingly focused on modern UX patterns.

Thanks for constantly pushing the platform forward — we’re excited about what’s coming next!

Warm regards,
Adriano

4 Likes

For those who can use it, I made an infinite scroll of 50 lines at a time like this:

1-In API query:

SELECT …. FROM …. ORDER BY….. OFFSET 0 ROWS FETCH NEXT CAST(:P1 AS INT) ROWS ONLY

Where :P1 Expression is {{$_GET.limit > 0 ? $_GET.limit : 50}}

2-On the data view page, before Server Connect:

<dmx-value id="currentLimit" value="50"></dmx-value>

3-Server Connect:

<dmx-serverconnect url="dmxConnect/api/api.aspx" dmx-param:limit="currentLimit.value"></dmx-serverconnect>

4- a hidden button used by Javascript to increment the limit and load more lines:

<button id="loadMoreBtn" style="display:none" dmx-on:click="currentLimit.setValue(currentLimit.value.toNumber() + 50)"></button>

5- Sentinel for infinite scroll (for IntersectionObserver in JS at the bottom page):

<div id="scrollSentinel" class="text-center" style="min-height:1px">  <div id="scrollSpinner" class="py-3" style="display:none">  <i class="fa fa-circle-o-notch fa-spin fa-2x text-secondary"></i> </div></div>

6-Finally, a script at the bottom of the page that implements the process:

<script>
        (function() {
        document.addEventListener('DOMContentLoaded', function() {
            var sentinel = document.getElementById('scrollSentinel');
            var spinner = document.getElementById('scrollSpinner');
            var loadMoreBtn = document.getElementById('loadMoreBtn');
            var tbody = document.getElementById('tableRepeat1');
 
            if (!sentinel || !loadMoreBtn || !tbody || !spinner) return;
 
            var allLoaded = false;
            var loading = false;
 
            // After LoadMore
            function loadMore() {
                if (loading || allLoaded) return;
                loading = true;
                spinner.style.display = '';
                var rowsBefore = tbody.children.length;
                loadMoreBtn.click();
 
                // Polling
                var checks = 0;
                var poll = setInterval(function() {
                    checks++;
                    var rowsNow = tbody.children.length;
                    if (rowsNow > rowsBefore) {
                        // Nuove righe caricate, tutto ok
                        clearInterval(poll);
                        loading = false;
                        spinner.style.display = 'none';
                    } else if (checks >= 15) {
                        // Dopo 3 secondi nessuna nuova riga: tutti i dati sono visibili
                        clearInterval(poll);
                        loading = false;
                        allLoaded = true;
                        spinner.style.display = 'none';
                    }
                }, 200);
            }
 
            // IntersectionObserver
            var io = new IntersectionObserver(function(entries) {
                if (entries\[0\].isIntersecting && !allLoaded && !loading && tbody.children.length > 0) {
                    loadMore();
                }
            }, { rootMargin: '200px' });
            io.observe(sentinel);
 
            // Reset
            var searchInput = document.getElementById('testofrm');
            if (searchInput) {
                searchInput.addEventListener('input', function() {
                    allLoaded = false;
                    loading = false;
                    spinner.style.display = 'none';
                });
            }
        });
    })();
    </script>

Made with the help of Claude AI
I hope it can be useful to someone, as it has been useful to me!