Alternative scroll behaviour option for internal links (to act like a standard link)

Currently, when clicking an internal link, the scroll is not scrolled to the top, and instead maintains the scroll position of the previous page. This is very different from standard links, where the browser discards the previous page’s scroll position and assumes the new page’s scroll is at the top.

If you haven’t noticed this behaviour, most likely you’re only using internal links at the navbar, which is usually at the top, hence you don’t see the scroll displacement issue.

It’s my opinion Wappler misconstructed this functionality as it goes against the behaviour one would expect from a standard browser experience.

The problem is, just like another issue in the past, some people have built Wappler apps with the expectation of this behaviour, and so changing the behaviour is not desirable. However, for people building new apps, this causes development friction as one needs to introduce additional steps (browser1.scrollYTo(0)) to ensure the scroll is at the top whenever an internal link is placed somewhere down the page.

I suggest to introduce some sort of switch that would allow internal links to behave like a standard link in terms of scroll position, both when clicking the link as well as going back to the previous page through the browser’s back button (popstate).

Reference:

We actually add scrollto to every single internal link.
Never struck me to create a FR for it.

I would suggest to add a checkbox for this in the browser goto option. And a flag attribute in anchor tag.

1 Like

I tried to solve this on my own by attempting to add the dmx-on:click to scroll to the top on every internal link automatically, but it seems Wappler framework removes Wappler attributes from the link so I can’t even do vanilla JS manipulation to add the Wappler attributes I want :sleepy:

Other thing I tried to do was to use Turbolinks instead of Wappler’s native internal links, but that didn’t work well with Wappler stuff either…

Hi @Apple,

As Sid mentioned in his post, I also add a scroll.goto action on each internal link. This is the code I add to the click event on a button to navigate to an internal link.

dmx-on:click="browser1.goto('/app/users',true);scroll1.goto('#pagetop')"

On the layout page, I add this code at the top inside the body tag <a id="pagetop" href="#"></a>

We use browser1.scrollYTo(0) like Apple. Does not need the pagetop element to be defined on each page.

Thanks Sid. Not sure why I set it up like that. I will modify it from now on :slight_smile:

How do I get this to work within content pages?

As the section inside the content page is what scrolls, not the layout page. Is there any way of getting a SPA to scroll to the top of the next section of content being shown? Considering all content is on 1 content page, and containers with forms are being hidden or shown depending on a dynamic value.

@Teodor @Apple @Hyperbytes Any ideas if possible? Thanks!

I'm not sure I follow the problem/requirement to be honest.

As an example scenario: I have a layout page with a menu containing links to multiple pages.
All these pages are content pages.
On click of any of those menu links, I would be redirected to the said page - internally - so SPA and no page reload.

Assuming here in the content page, that you scroll at the bottom, and then select some other page from the menu in layout page.. you expect the page to scroll to top when you are navigated to the new content page.
EDIT: Simplest option would be to configure a page flow on each of the content pages, with browser.scroll step.
Simplest option would be to create an App flow, with the scroll step.. and then add the app flow on every content page and set it to "autorun".

Or, if you don't have any other source of getting to the content pages, except the layout menu, you can configure dynamic click event on each of the menu items itself, with the scroll step.

Hope this helps/makes sense.

So scenario is that I have a long form which when filling out user must scroll to bottom to click the next button. When the next button is clicked and SC form is successful, a dmx value is updated which will then hide the completed form and show the next form. The problem is that when the new form loads, it is already scrolled to the bottom which i understand is wappler behaviour, but i would like to take them to the top of the form, bare in mind the page has not reloaded at this point, nor done an internal load. It has simply performed a server connect api, then on success has loaded the next form. I hope that helps.

Makes much more sense, thanks.
So, on dynamic updated event of the variable, you can setup browser scroll function.

1 Like

Yeh so I've tried the ScrollYto(0) on this dynamic event of the variable, however nothing happens, and I've also displayed the scroll value on the top and bottom of the form to see if it changes. And unfortuantly i think it doesn't work due to the scrolling happening in the content section, as apposed to the layout page itself. So hence looking for other solutions.

I managed to get the form to move down if I use an ID of a row. However it jumps and is not smooth even using smooth scroll, and it also only happens once even if the same button or is clicked. So any other ideas would be great!

Thanks

Oh I see. You don't have any scrolling on the page itself, but inside the content page container.

We use a custom JS function for such cases:

function ScrollDiv(element) {
  if (document.getElementById(element)) {
    document.getElementById(element).scrollTop = 0;
  }
}

Also, we apply smooth scroll on such inner scrolling elements like so:

.smooth-scroll {
  scroll-behavior: smooth !important;
}

Hi @sid

Thank you for your suggestion. I haven't had much luck implementing it, are you able to provide any further details as to how this should work?

When I'm clicking a button, I am scrolled all the way down inside a content page container. The sequence of events occurs on the button click, and I've tried calling this function with the ID of the container for my next form which will show based on a variable value changing. But the page stays in the same view. I have added a console log to the script and can confirm the script is being called.

Button calling:

<button id="Summary_submit1" class="btn btn-primary style22 mt-2 mb-2" dmx-on:click="run([{run:{outputType:'text',action:`preloader1.show()`}},{wait:{delay:1000}},{run:{outputType:'text',action:`steps.setValue(\'PAYMENT\')`}},{run:{outputType:'text',action:`preloader1.hide()`}},{wait:{delay:500}},{runJS:{function:'ScrollDiv', args:['PaymentContainer']}}])">{{LanguagePack.data.LPArray_Button.ContinueToPayButton[0].value}}</button>

Container trying to scroll to the top of:

<div class="container pt-3 pb-2" id="PaymentContainer" dmx-show="steps.value=='PAYMENT'">
//Modal code in here usually
<form method="post" action="/api/Payment" is="dmx-serverconnect-form" id="Payment" dmx-on:success="run([{run:{outputType:'text',action:`paymentModal.toggle()`}},{run:{outputType:'text',action:`Opayo_Timeout_timer.start();opayo_minute_countdown.start()`}},{run:{outputType:'text',action:`Payment_Status_Response.setValue(\'INPROGRESS\')`}}])" dmx-on:submit="" dmx-on:error="notifies1.danger(lastError.message)" dmx-on:start="preloader1.show()">
            <div class="row justify-content-around">
                <div class="col-12 border-2 rounded-2 border border-secondary align-self-center col-md-10 col-xxl-6 col-lg-8 col-xl-7 col-sm-12 bg-body">
                    <div class="row justify-content-center mb-2 ms-0 me-0">
                        <div class="col text-center mt-1">
                            <h1 class="pt-3 pb-3">{{LanguagePack.data.LPArray_Payment.PaymentTitlePrimary[0].value}}</h1>

//More form stuff

Thanks
Tom

The setup looks ok.
Can you try to run the function directly in browser console to check if it has any effect on the container or not?
Also, are you sure this is the container which has the scroll, and not some other parent or child div?

Hi Sid,

Thanks for your reply, I will give this a go when I next get a chance!

Thanks

Hi @sid

Thank you for your help on this.

My solution has been a little different to things discussed here.

I have a container which contains further individual containers per Form / stage of my process. Instead of using the id: 'forms' as my reference for the smooth scroll component, I added this as the first line of the container, here's an example:

<div class="container" id="Forms">
    <dmx-value id="top"></dmx-value>
    <div class="container pt-3 pb-2" id="FirstContainer" dmx-show="steps.value=='SomeDynamicValue'">
       <form id="firstFormID" //extra form stuff here>

Then whenever I needed it to scroll to the top of a form, I would add a run action to my form onSuccess flow for the smoothScroll as follows:

 {run:{outputType:'text',action:`scroll1.goto(\'#top\')`}}

After messing with some enter and leave animations, durations and other aspects, this now functions as I'd want it to.

Thanks to all that offered help with this, and I hope this can help anyone else struggling with this in the future!

Tom