Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jumping to fragments does not work in a good way in `Browser.application` #39

Open
ChristophP opened this Issue Sep 20, 2018 · 1 comment

Comments

Projects
None yet
1 participant
@ChristophP
Copy link

ChristophP commented Sep 20, 2018

For a Browser.application the docs recommend to handle UrlRequest like this

case msg of
    ClickedLink urlRequest ->
      case urlRequest of
        Internal url -> ( model, Nav.pushUrl model.key (Url.toString url))
        External url -> ( model, Nav.load url )

However, this won't do anything with links like the following <a href="#someAnchor">Jump</a> (to jump to <a name="someAnchor"></a>) since they will count as Internal UrlRequests.
It is possible to jump to fragments using Nav.load but the suggested code above will only change the url with Nav.pushUrl.

Notes:
There are a couple of cases to consider, links like:

  1. #myAnchor or /samePage#myAnchor
    Links pointing to anchors on the same page can be used to safely jump to the anchor immediately using the browsers default behavior, because the page is already rendered.
  2. /newPageAnchor#anchorOnDifferentPage
    However when navigating to an new page an anchor on a new page, SPAs behave differently than server rendered pages. The url changes first and only after some async data is loading the page containing the anchor is actually rendered. Only once the page is rendered it is possible to jump to the anchor. This case introduces a time gap between clicking the link and being able to navigate to the anchor.

It would be nice to have a solution for the first case that is close to browser behavior, but the preventDefault on every link seems to make it tough right now.
The second case (navigating to a new page) doesn't seem to be elm specific but a general SPA "problem". Other frameworks and routers have similar issues https://github.com/rafrex/react-router-hash-link/tree/react-router-v2/3#react-router-hash-link-scroll and seem to use some kind of polling of the DOM to check if the anchor has been rendered.

@ChristophP

This comment has been minimized.

Copy link
Author

ChristophP commented Nov 3, 2018

Update

After giving this a lot of thought, I would like to suggest to add an additional check in the vdom to prevent the default on link clicks only when this is also true:

domNode.getAttribute('href')[0] !== '#' 

This will preserve regular browser behavior for links which just reference an anchor and won't send the msg to the Browser.application. This will take care of the most common case for using anchor (go to anchor on same route) which is case 1 talked about above. Of course there are also other cases like going to a new page with an anchor (case 2 above) but those will need to be handled anyway in SPAs and the jump to the anchor needs to be delayed until the anchor is rendered.
This suggested fix could be a good way to get some of the browser fragment link behavior back that is now taken away by the prevent default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.