How to make anchors work when switching between two routes in a Bolero F# single-page app

42 views Asked by At

I used html templates and defined navigation bar like this

   <a href="${Page1Link}" class="navbar-brand">Page1</a>

...
    <div class="collapse navbar-collapse" id="navmenu">
      <ul class="navbar-nav ms-auto">
        <li class="nav-item">
          <a href="${Page1Link}#section1" class="nav-link">Section1</a>
        </li>
        <li class="nav-item">
          <a href="#section1" class="nav-link">Section1</a>
        </li>
        <li class="nav-item">
          <a href="${Section1Link}" class="nav-link">Section1</a>
        </li>
        <li class="nav-item">
          <a href="${Page2Link}" class="nav-link">Page2</a>
        </li>
      </ul>
    </div>

The model has one page where

type Page =
    | [<EndPoint "/page1">] Page1
    | [<EndPoint "/page1#section1">] Section1
    | [<EndPoint "/page2">] Page2

I want to switch from page2 to page1 and scroll to the section.

Page1 and Page2 links work just fine. #section1 works on the page1, but of course, it doesn't work on page 2. Section1Link works as Page1 link, i.e. it switches the page but doesn't scroll. ${Page1Link}#section1 works as just #section1.

Besides defining achors I think this might help

<script>
      window.scrollToSection = function (sectionId) {
          var element = document.getElementById(sectionId);
          if (element) {
              element.scrollIntoView({ behavior: "smooth" });
          }
      };`
</script>

but I don't understand how to invoke the function when the router switches the page.

1

There are 1 answers

2
Tarmil On BEST ANSWER

As the lead maintainer of Bolero, I would say that we probably won't implement something like [<Endpoint "/page1#section1">]. Having /page1 and /page1#section1 as two different endpoints would allow the view to render them as two different contents, which is inconsistent.

However, supporting ${Page1Link}#section1 would be nice. I just created an issue for this.

Edit: For your workaround, you should be able to use JS interop in the update function. Something like this:

let update (js: IJSRuntime) message model =
    match message with
    | SetPage p ->
        let cmd = Cmd.OfJS.attempt js "scrollToSection" [||] Error
        { model with page = p }, cmd

and then instead of having scrollToSection take the section as argument, it can directly use window.location.hash.substr(1).