Reading LiveView assigns in app.html.eex

I am trying to create applications with Phoenix LiveView. I find it awesome and extremely powerful for providing rich client experience. Thanks.
I have a situation where say I have 5 live routes Page 1 to Page 5 each rendered using their own live view.
I have created a menu in app.html.eex.

<ul>
  <li><a href="/page1">Page 1</a></li>
  <li><a href="/page2">Page 2</a></li>
  <li><a href="/page3">Page 3</a></li>
  <li><a href="/page4">Page 4</a></li>
  <li><a href="/page5">Page 5</a></li>
</ul>

Now i want to highlight the corresponding menu item when the user navigates to a page. For ex if user is in Page 3 i want to highlight the Page 3 menu item and so on.
I have created an assign called current_page in all the live views and set it accordingly.

assign(socket, %{
  ...
  current_page: "page1"
})

But I am not able to query that assign in the app.html.eex. I think because conn assigns and socket assigns are different.

How can i access socket assigns from outside of it or from the parent view like layout view or app.html.eex.
Or is there some other way to solve this problem using liveview.
Thank you so much for giving your time and help.

Hi @sreyansjain. Conn assigns and socket assigns are definitely different, if you’re accessing assigns in the root layout those need to be on the conn.

But how to i set conn assigns from with the liveview?

You can’t, you need to set them on the conn. How are you rendering the live view? Directly from the router via live ?

Yes, directly from the router.

In that case you need to set those assigns via a plug, or move them into the live view. I have a pattern for having most of the layout be live viewed that I can elaborate on tomorrow if necessary as well.

1 Like

Thanks. That would really help.

My fallback is rendering the live view inside a normal view and setting the conn assigns in the controller.
That would mean a few extra routes, but it would get the job done.
I am really looking forward to your solution @benwilson512. Thank you so much.

In the short term you can remove those controllers by just adding a plug to your pipeline that sets the common assigns.

1 Like

I got it to work by using a plug. Thank you so much. If you have time, i would be really grateful if you can share your pattern for live views. Thank you so so much.

@sreyansjain, can you post the code of the Plug example ?

pipeline :login_required do
  plug(Guardian.Plug.EnsureAuthenticated)
  plug(:put_user_token)
end

defp put_user_token(conn, _) do
  conn = 
  cond do
    Enum.member?(conn.path_info, "xyz") -> Plug.Conn.assign(conn, :page_name, "XYZ Hub")
    Enum.member?(conn.path_info, "abx") -> Plug.Conn.assign(conn, :page_name, "ABC Box")
    true ->
      Plug.Conn.assign(conn, :page_name, "Home")
  end
  user = Myapp.Guardian.Plug.current_resource(conn)
  token = Phoenix.Token.sign(conn, "user socket", user.username)
  conn = Plug.Conn.assign(conn, :client_user, user.username)
        |>  Plug.Conn.assign(:user_id, user.id)
        |> put_session(:user_id, user.id)
  assign(conn, :user_token, token)
end
scope "/", MyappWeb do
    pipe_through([:browser, :client_auth, :login_required])

    live("/change_password", ChangePasswordLive, session: [:user_id])
    ....
end
2 Likes