How do I get path parameters in LiveView?

My router:

live "/cities/:id/users", CityLive

I tried the handle_params function but it was never called:

def handle_params(%{"id" => id}, _uri, socket) do
  # some code

I tried to follow the practice in the chrismccord/phoenix_live_view_example project and still failed (session is always %{}):

def mount(%{path_params: %{"id" => id}}, socket) do
  # some code

Can see the parameters from the log:

Can anyone tell me what is missing?

If your liveview is mounted in the router and is the root one (not nested) it should work with handle_params. I did use that a few days ago. If that‘s not the case you should be able to supply the param as part of the session data you supply for live_render.

1 Like

You need to specify path_params as part of the live route session:

live "/cities/:id/users", CityLive,
  session: [:path_params]
1 Like

I still have not succeeded. path_params is always nil. :frowning:

You can only receive path params via the handle_params/3 callback, and handle_params is only invoked for the root LV. If you are trying to get path params to a child, you need to retrieve them from the root and pass them down to the children via assigns in the parent


Maybe I misunderstood what? This is the root LV, which is not loaded from the parent LV. I can get the query parameters of the same level LV from handle_params, but I can’t get the path parameters.

The code is at:

Thanks for the reply from the author!

The params contain the merged path params and query param so “id” should be there. Can you provide the entire LV?

I made a mistake, sorry! A very small mistake! This problem is invalid :joy:

This problem does not exist because I wrote the wrong number of handle_params parameters.

Thank you all :pray: :pray:

1 Like

I too am tripped up by this. Maybe the for CRUD user are out of date and need to be updated?

For example on: phoenix_live_view_example/lib/demo_web/live/user_live/show.ex

  def mount(%{path_params: %{"id" => id}}, socket) do
    if connected?(socket), do: Demo.Accounts.subscribe(id)
    {:ok, fetch(assign(socket, id: id))}

will break on localhost:4000/users/1 with error: no function clause matching in DemoWeb.UserLive.Show.mount/2 because the received first arg %{} can never match %{path_params: %{"id" => id}}

If the recommendation is to now use handle_params/3 to get the path_params, (which handle_params/3 is called sometime after mount/2) does that mean that it is not possible to fetch the User data in mount/2 for the first render?

Hi @homanchou,

Yes the CRUD user example is out of date. This working unmerged PR addresses it by using handle_params/3 to get the user by id instead of mount/2:


I’m curious how this new api works regarding the first server side render. If I understand correctly, rendering the page used to happen immediately after mount/2. Does it now happen after handle_params/3 in order to avoid flash of a blank page on first paint?

This is not the case. handle_params gets called once between the first call of mount and the first call of render.


Hello All,
I found this thread while trying to get params for a “router” liveview.
This has changed very recently (with version 0.6.0) so I put this as a reminder for future readers.

Now it is possible to get params (url ids + querystrings) directly from mount/3 which now accepts params as a first argument, ex :

def mount(%{"id" => id, "token" => token} = params, session, socket) do

I think this is the correct way of handling it as of today :wink:



Useful clarification recently added by Jose when deciding whether to use mount or handle_params

Note the parameters given to c:handle_params/3 are the same as the ones given
to c:mount/3. So how do you decide which callback to use to load data?
Generally speaking, data should always be loaded on c:mount/3, since c:mount/3
is invoked once per LiveView life-cycle. Only the params you expect to be changed
via live_patch/2 or push_patch/2 must be loaded on c:handle_params/3.

1 Like