How do you build URLs in your views while maintaining query params?

I have an app where the vast majority of it exists in a single liveview, with multiple states managed by the route…

/trips/{trip_id}
/trips/{trip_id}/edit
/trips/{trip_id}/items/{item_id}
/trips/{trip_id}/items/new
/trips/{trip_id}/items/{item_id}/edit

I also have query params that I want to persist throughout any changes between the above routes…

?label=food
?completed=true
?category=plans

The issue I quickly ran into is I’d add a new query param, but then forget to add it to all the places I was building a sigil p route. So when transitioning from edit trip to show trip, I forgot to include that param and it was dropped. I’ve currently solved this by making URL builder functions that take a ton of variables, so at least when I add a new param, the compiler will complain that build_trip_route/3 does not exist.

Does anyone have a cleaner solution to this? I think the ideal for me would be one where I could get all the existing query params by default, and just occasionally override them when needed (eg to set label=nil).

Thanks!

2 Likes

Hmm, verified routes lets you dynamically add multiple query params at once when interpolating a map.

<.link to={~p"/users?#{@params}"}>profile</.link>

So assuming you’re tracking the query params in the socket assigns e.g. via attach_hook on handle_params within the on_mount callback as demonstrated in the LiveBeats’ Nav component, you shouldn’t need to manually update all your verified routes when adding a new query param.

5 Likes

Ah nice, I missed that you can just throw a map straight in. Thank you! How about overriding a single value?

<.link to={~p"/users?#{Map.put(@params, :label, new_label}"}>profile</.link>
1 Like

What triggers the change in label?

Just speculating, but if the label query param only applies to trip routes but not nested item routes then you could handle the override in the handle_params callback by using Map.put or Map.drop. You could also use a separate assign for the overriden assign to avoid losing the label query param when switching from a trip route that uses it to an item route that doesn’t and back to a trip route that does. It’s also possible to tag live routes with metadata if you wanted to explicitly declare what query params are permitted or dropped for each route.