Get URL within on_mount function

Hi :hand_with_index_finger_and_thumb_crossed:

I am trying to pass the current url around for the purpose of something similar to “current active tab”.

I realize the best way (maybe there are better ways) to accomplish this is via live_session and on_mount function.

But, how do I get the URL within on_mount function? just like the handle_params did.

Code:

defmodule WoohooWeb.InitAssigns do
  @moduledoc """
  Ensures common `assigns` are applied to all LiveViews attaching this hook.
  """
  import Phoenix.LiveView

  alias Woohoo.Accounts
  alias Woohoo.Accounts.User

  def on_mount(:default, _params, session, socket) do
    socket = assign_defaults(session, socket)

    {:cont, socket}
  end

  def on_mount(:user, _params, session, socket) do
    socket = assign_defaults(session, socket)

    {:cont, socket}
  end

  def on_mount(:admin, _params, _session, socket) do
    {:cont, socket}
  end

  defp assign_defaults(session, socket) do
    socket = assign_new(socket, :current_user, fn -> find_current_user(session) end)
    socket
  end

  defp find_current_user(session) do
    with user_token when not is_nil(user_token) <- session["user_token"],
         %User{} = user <- Accounts.get_user_by_session_token(user_token),
         do: user
  end
end
1 Like

Wouldn’t that be nice? You simply can’t. the url is currently only available from within the handle_params/3 callback. So if you want to replicate some logic like “current active tab” across your views, you’ll have to replicate that callback everywhere. My current solution is to define the callback in the __using__/1 macro of a module and then have all views use that module.

Oh, and if you’re thinking of live_render a subview in a template and put the logic in there, that won’t work either because handle_params/3 only works for top-level views.

Bummer, I say :slight_smile:

You can maybe attach a hook for handle_params from within on_mount.

3 Likes

Just read about it.

is this what you mean?

defmodule WoohooWeb.InitAssigns do
  import Phoenix.LiveView

  def on_mount(:default, _params, session, socket) do
    socket = assign_defaults(session, socket)

    {:cont, socket}
  end

  defp assign_defaults(session, socket) do
    socket =
      attach_hook(socket, :set_current_path, :handle_params, fn
        _params, url, socket ->
          {:cont, assign(socket, current_path: URI.parse(url).path)}
      end)

    socket
  end
end
4 Likes

yes exactly :slight_smile:

Yeah, sorry for my dumb answer. That looks great, I’m gonna try it out soon!

@chrismccord Woohoo Thanks!

@trisolaran thanks for your answer anyway. Nothing wrong here, I am new and learning anyway :slight_smile:

1 Like

In one of my projects it was useful to have the :path_info and :query_string conn fields on the socket. Here’s what I did if it helps anyone

  def on_mount(:assign_path_info, _params, _session, socket) do
    {:cont, attach_hook(socket, :path_info, :handle_params, &assign_path_info/3)}
  end

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

    {:cont,
     socket
     |> assign(:path_info, parse_path_info(parsed_uri.path))
     |> assign(:query_string, parsed_uri.query || "")}
  end

  defp parse_path_info(nil), do: []
  defp parse_path_info("/"), do: []
  defp parse_path_info(""), do: []

  defp parse_path_info(path) do
    path |> String.trim_leading("/") |> String.split("/")
  end
1 Like