LiveView push_patch append to params

I’m creating a search form with filters and want both the query and the filters to change the URL. The filters and query can be set separately or together, and handle_params can already deal with either being empty.

What I’m doing is triggering a push_patch on events (filter click, form submit, clear search). Something like this:

  def handle_event("update_filter", %{"filter" => filter}, socket) do
    {:noreply,
     push_patch(socket,
       to: Routes.live_path(socket, Index, query: socket.assigns.query, filter: filter)
     )}
  end

  def handle_event("search", %{"query" => query}, socket) do
    {:noreply,
     push_patch(socket,
       to: Routes.live_path(socket, Index, query: query, filter: socket.assigns.filter)
     )}
  end

This works, but my “problem” is that I have to set all the url params every time I call push_patch. Is there any way to say append this param to the current path? Alternatively, is there any other design pattern I should be following to set this up?

I set up events to do exactly what you’re doing but with a different problem, but I wonder, does it make more sense to use live_patch links from your template with the query params in tact and then use handle_params at the LV level to grab those params?

This means the event handler would go away and having to push_patch from the LV itself since live_patch already pushes it to the URL.

Just asking because the above applies to your example too. I wonder what folks think about this. What would be the way to do this?

What’s interesting is the --live generator from Phoenix 1.5 includes making a search form using the event style but in their case, they are doing an external redirect so maybe the use case is different.

The reason I’m not using live_patch is because both filter and search are independent generic components and I don’t want to have to pass all the assigns to both. Instead, whenever they are “used”, they send the parent an event saying “Hey, someone searched for X” or “Hey, someone filtered by Y”.

If I was able to use live_patch to add to the existing URL, instead of replacing it, then I would be able to use it generically.

2 Likes

Would you mind gisting the complete code for those components and how this parent event is sent?

How to try it. I tried generating but no search feature got generated.

mix phx.gen.live Masters Item items item

No search thing got generated.

I’m using Surface, but you can do the same with regular LiveView.

I have the same problem. Desperate for a solution… Cleaner push_patch and handle_params?

Here is how I solved it in my app:

  1. I store the params in handle_params as part of the assigns:

     def handle_params(params, url, socket) do
       # You could store the params as is but I like to store
       # only what has been parsed/validated.
       params = parse_params(params)
       {:noreply, assign(socket, :params, params)
     end
    
  2. Create a helper called self_path:

     def self_path(socket, action, extra) do
       Routes.live_path(socket, __MODULE__, action, Enum.into(extra, socket.assign.params))
     end
    
  3. Now I do:

     push_path(socket, to: self_path(socket, :search, %{"sort_by" => "foo"}))
3 Likes