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

Suggestion: Allow reacting to search params and fragment changes on the client side #509

Open
agj opened this issue Jan 7, 2025 · 10 comments

Comments

@agj
Copy link

agj commented Jan 7, 2025

Some way to react within the route itself to changes in the URL involving search params (?) and the fragment (#). Something like Elm Land's Page.withOnUrlChanged, although I haven't used that personally.

My personal use case is that I have a static blog built with elm-pages, and one page is the tag page, which uses a ?t=tag query to list posts matching a tag. I was able to do this with v2 because when the URL changed, the page re-initted, so the model was rebuilt.

@ymtszw
Copy link

ymtszw commented Feb 6, 2025

I'm almost finished with migrating my site to v3 from v2, and found this exact issue is the most punishing one.
@dillonkearns Is there any records of discussion about this?

Client-side routing using query parameters or fragments have not-so-insignificant use-cases IMO, and should be definitely supported.

  • Most typically, we want let users to "store" client-side state as query params or fragments
    • Table state, such as sorting/filtering conditions
    • In-page anchor
    • etc.
  • These are not something we handle in server-render, since they are not necessarily altering contents inside a page. Just how they are viewed
  • With URL, you can share the state across multiple devices/browsers through bookmarks, or even with someone else
    • This is why it cannot be completely replaced with storing state in localStorage

Currently (elm-pages 10.2.0) query params or fragments CAN be read and used in Route modules' init only on initial page load, but not after client-side application started (i.e. after clicking a link in the page).
This might actually be a bug or oversight rather than design issue, but at least I could not trace down the relevant part in the code.

BTW, for now I'm patching my site so that links with query params or fragments to have accompanying onClick side-effects to reproduce desired behavior. While cumbersome, it is a workaround for sure.

@dillonkearns
Copy link
Owner

dillonkearns commented Feb 6, 2025

Yes I think it's just an oversight @ymtszw. I think RouteBuilder.withOnUrlChanged is basically the missing piece, does that sound right to you?

@ymtszw
Copy link

ymtszw commented Feb 6, 2025

@dillonkearns That sounds okay, but is there any thought behind not triggering init of route modules? Like bare Elm SPAs or elm-pages v2?

@dillonkearns
Copy link
Owner

I'm not following, could you elaborate on what you mean there?

I don't see any reason that init should be called except for when going to a new Route, and the query params and hash parts of the URL don't effect that so they should not result in init being called for the Route.

Like bare Elm SPAs or elm-pages v2?

Elm SPAs don't have a built in concept of a Route, so not sure what you mean here?

@ymtszw
Copy link

ymtszw commented Feb 6, 2025

What I mean is, in bare Elm SPA or elm-pages v2 app, simply putting a [ href ("?param=" ++ whatever) ] [ text "New param" ] and let users click on them can initiate "routing" behavior.
I.e. Elm runtime to capture the link click event, call onUrlChange callback in Elm SPA case, where we wire our own "Route" or "Page" module routing mechanisms. At least in my daily projects and elm-pages v2 project this was the case.
I believe this also is the reason behind #479 too. Am I clear enough?

@dillonkearns
Copy link
Owner

No I'm still not following. Are you talking about creating links, or handling URL changes? #479 is about creating links, not responding to links.

You can manually create links easily without the built-in type-safe helpers, you just need to add the low-level Html.Attributes.attribute "elm-pages:prefetch" "" if you want it to perform pre-fetching on it. I don't think we should discuss building links in this issue as it makes things confusing, let's keep this issue to discussing handling URL changes.

@ymtszw
Copy link

ymtszw commented Feb 6, 2025

The issue on creating links (#479) is auxilliary, just for convenience.
I'm primarily talking about handling URL changes here.

In v3 currently, if we put the internal links but if that URL does not alter "path" part (i.e. targeting Route) from the URL where the user currently is, there are no way to capture the URL change. This is the issue that OP describes.

And I BELIEVE this can be achieved without adding additional API (withOnUrlChanged) but rather elm-pages just call init of the Route module when such URL change detected, so was the question occured to me.

@dillonkearns
Copy link
Owner

I don't think think the semantics of calling init to allow users to capture this are intuitive or useful. This would technically allow you to not introduce a new withOnUrlChanged function in order to handle these changes, but it would also be a sudden semantic changer for users who might not be expecting that. For example, if they have any Effects on init, it would cause those to get re-run, which doesn't make sense, and they would have no way to avoid that. So I don't see any reason to do that, it's completely fine to introduce the additional function for use by anyone who needs that functionality.

@ymtszw
Copy link

ymtszw commented Feb 6, 2025

That sounds reasonable I see 👍

In my personal cases I had mostly implemented my inits either idempotent or at least re-run-tolerant. That's why I was totally OK with going through init again for this "functionality". But yeah, cases vary.

@dillonkearns
Copy link
Owner

Even if they're re-run tolerant, it would be surprising to have init Effect's re-running on every URL change, especially if you are rapidly changing them. For example, if you change them on every keystroke. So it would break some use cases in an unsolvable way. Whereas withOnUrlChanged works totally fine for both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants