zamith
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?
Most Liked
josevalim
Here is how I solved it in my app:
-
I store the
paramsinhandle_paramsas 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 -
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 -
Now I do:
push_path(socket, to: self_path(socket, :search, %{"sort_by" => "foo"}))
sb8244
FWIW, you can also directly use the URI rather than calling the Routes helpers. The above code does this as well, but I wanted to provide a more concise version if you don’t need as many bells and whistles.
def handle_params(_params, uri, socket) do
{:noreply, assign(socket, :uri, URI.parse(uri))}
end
def handle_event("prev_page", _, socket = %{assigns: %{pager: %{page: page}, uri: uri}}) do
current_params = URI.decode_query(uri.query || "")
new_params = Map.put(current_params, "page", page - 1)
to = uri.path <> "?" <> URI.encode_query(new_params)
{:noreply, push_patch(socket, to: to)}
end
seva
Worth adding that instead of URI.decode_query/1 and URI.encode_query/1, you might want to use more robust Plug.Conn.Query.decode/1 and Plug.Conn.Query.encode/1, which do better encoding/decoding of lists in URL (e.g. ?ids[]=1&ids[]=2).
I.e.
URI.decode_query("ids[]=1&ids[]=2")
# => %{"ids[]" => "2"}
Plug.Conn.Query.decode("ids[]=1&ids[]=2")
# => %{"ids" => ["1", "2"]}
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









