Raees678

Raees678

How can I obtain the current url to pass to a functional component from the app.html.heex layout when rendering liveviews?

I have a sidebar as a function component that takes the current route as well as a list of items to display:

[%{
  title: "some title",
  route: ~p"/some/route"
}, ...]

The sidebar displays all of the items vertically, and if any of their routes matches the current route, then it adds a little highlight to display the currently selected page.

But now I would like to embed this into my layout, so that all dead and LiveViews can use this. So I put this in my app layout, since I would like the highlighted item to update if i live_redirect. But here is where I run into my issue.
If my app is rendering a dead view, I can access the @conn variable here, and obtain the current route to pass to my sidebar component. But if it is rendering a LiveView @conn is not available, and I must use @socket, where the current route is not available. Is there a way I can obtain the current route from the socket, or is there any other solution for obtaining the current route form the layout regardless if the page being rendered is a dead view/LiveView, and also one that updates across live_redirects etc.

Most Liked

sodapopcan

sodapopcan

You can assign @current_path in both a plug and a LiveView hook (not to be confused with a js hook).

Plug:

defmodule MyAppWeb.Plugs do
  import Plug.Conn
  import Phoenix.Controller

  def assign_current_path(conn, _) do
    assign(conn, :current_path, current_path(conn))
  end
end

…and add to your browser pipeline in the router:

MyAppWeb.Router do
  # ...
  import MyAppWeb.Plugs

  pipeline :browser do
    # ...
    plug :assign_current_path
  end
end

Live Hook:

defmodule MyAppWeb.LiveHooks do
  import Phoenix.Component, only: [assign: 3]
  import Phoenix.LiveView, only: [attach_hook: 4]

  def on_mount(:global, _params, _session, socket) do
    socket =
      attach_hook(socket, :assign_current_path, :handle_params, &assign_current_path/3)

    {:cont, socket}
  end

  defp assign_current_path(_params, uri, socket) do
    uri = URI.parse(uri)

    {:cont, assign(socket, :current_path, uri.path)}
  end
end

…and attach the hook in your router:

live_session :some_name, on_mount: [{MyAppWeb.LiveHooks, :global}] do
  # ...
end

(:global can be something more descriptive if you like)

Now @current_path is always available in the layout whether rendered by a live or dead view.

You can use these methods to stuff other data into assigns as well.

EDIT: I forgot the router portion for the plug… see above.

2ND EDIT: Sorry, @brady131313, I blew past your message that offered the same hook advice.

Raees678

Raees678

I thought this too, but this does not work in the app.html.heex file. I need the sidebar in this is the file since it is the layout that embeds the <.sidebar current_url={...} items={...}/> component, in all views (both dead views and liveviews).

I think the file is just a template, that I’m assuming compiles down to a function body in the layouts.ex file, similar to how other .heex files get converted into function bodies in the respective controller etc. Since the layout.ex file isn’t a LiveView, putting handle_params in that file doesn’t work. Even attaching a hook doesn’t work since the socket.assigns themselves are unavailable at the time that app.html.heex is evaluated. If I try to print them, even with a hook attached, the value of the assigns is Phoenix.LiveView.Socket.AssignsNotInSocket<>.

Raees678

Raees678

I tried this as well, but this does not work for another reason. If you use live_render then handle_params isn’t invoked, and the app doesn’t even compile, and throws an error. handle_params is only ever invoked for live routes in the router.

Last Post!

bo_dev

bo_dev

Don’t be sorry, Soda. I am a complete beginner, and your example has been incredibly helpful.

Where Next?

Popular in Questions Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Other popular topics Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44532 311
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New

We're in Beta

About us Mission Statement