Open Sushisource opened 6 years ago
Single-page app routing with the hash essentially "hijacks" the usual purpose of the hash, so you can't then easily also use the hash to navigate to an anchor on your page in the usual manner. There is, after all, only one hash (from the browser's point of view) -- there's no (simple) way to tell the browser to ignore the first part of the hash and navigate to an anchor represented by the second part of the hash.
In fact, look at the docs for RouteUrl.Builder.fromHash
-- that describes how a "hash within a hash" is encoded. (Since you can only have one hash, really).
So, to support navigating to a particular spot within a page (i.e. what a hash usually does), you've basically got two choices, I think:
You could try putting the "elm-route-url" routing stuff in the URL itself (not the hash), and use the hash for its usual purpose, to refer to an anchor. In this case, you'd need to parse the path for elm-route-url (instead of the hash), and your server would have to know which page to send (i.e. the same page, even though the path differs.
Though, I don't think that can be made to work in a straight-forward way, because (as you note) the anchor doesn't exist immediately -- it only exists when the Elm code constructs it. So, the browser can't actually go the anchor, at least if you're refreshing the page, because the anchor won't exist yet at the moment the browser looks for it. I suppose you could create a port
which, when it receives a message, navigates to the hash, and send that port a message on a delay (so that the anchor exists by then).
So, the better way is to handle it programmatically. But this is actually awkward too, because I don't think that elm-lang/dom
has the equivalent of Javascript's scrollIntoView
, which is the sort of thing you'd need. You can find it in https://github.com/gdotdesign/elm-dom, so that would be an option.
In any event, the idea there would be that you would parse the URL using elm-route-url, and part of your url scheme (in whatever way you like) would indicate an anchor on the page to go to, and so you could generate a message that would scroll the relevant element into view.
In fact, on second thought, you could create a port that uses scrollIntoView
in order to implement the message (so you wouldn't necessarily need something like https://github.com/gdotdesign/elm-dom).
Anyway, I hope that puts you on the right track -- basically, it's not possible to use the hash to go to an anchor in the usual way, but there are some other approaches that can be made to work.
Thanks! That definitely helps. I'll see about using the hash-less version with the port for scrolling, that seems pretty reasonable. Might be worth putting some of this into the docs for the curious - something about not expecting anchors to work by default I expect would be useful. Happy to open a PR with something reasonably concise if that'd help.
Hi there!
Liking this package a lot - but I've run into a bit of trouble. I'm not sure anchors are compatible with the way the hash URL currently works, but maybe I'm just doing something stupid.
I have an app with the router set up like so (a bunch of it elided for readability)
Basically the only thing I'm doing is, after the
hostname/elm.html#!/
I have a number which is some ID for stuff I need to fetch from the server and render. So my url normally looks likehostname/elm.html#!/123456
for example.As it stands, the anchors work, but they mess up the URL to be
hostname/elm.html#ev-1
When what I want is
hostname/elm.html#!/123456#ev-1
The problem being this breaks history/refresh/url sharing.
I think I may be doing something wrong insofar as instead of setting
href #ev-1
on my links, I should be having onClick generate some action which appends to the url - but I'm not 100% on how to do that without adding a "current anchor" field to my model or something, which feels a little overkill.That said, maybe that's what I've got to do, given that providing a bookmark like this doesn't really work since the element doesn't exist until pageload is complete, which is a general elm problem and not specific to this package.
It feels a touch clunky to me so I'm wondering if there's a prettier way to do this or if that's just what I need to go ahead and do.
In any case, there is one thing that definitely seems like it's not working: If I manually enter
hostname/elm.html#!/123456#ev-1
into my url bar and hit enter, nothing about#ev-1
shows up in the console:Thanks!