Page title via live view route that’s compatible with existing code in regular views?

Hi,

Here’s the code I use to set the page title in my Layout template:

<title><%= @view_module.title(action_name(@conn), assigns) %></title>

Here’s a sample of what I have in one of my Views:

defmodule ZoinksWeb.TaskView do
  use ZoinksWeb, :view
  alias ZoinksWeb.TaskLive

  def title(_action, _assigns), do: "Tasks"
end

However, now that I’m trying to implement Live View - @view_module ends up being “Phoenix.LiveView.Controller” (rather than a user-defined view).

Is there something I can do with Live View that will work with regular Views that’s similar to my existing solution? Or should I just regress to setting an assign in the controller and/or live view?

I don’t think you can do this right now with LiveView. But I do know that browser pushState support is on the roadmap, so I would not be too surprised if updating the page title would also be part of this.

3 Likes

I think I’ve figured out a way to do it. Looks like there’s a @live_view_module assign. Here’s what my title tag looks like now:

<title><%= title(@conn, assigns) %></title>

In LayoutView, this is what the title function looks like:

def title(conn, assigns) do
  try do
    cond do
      assigns |> Map.has_key?(:live_view_module) ->
        module = assigns[:live_view_module]
        module.title()

      assigns |> Map.has_key?(:view_module) ->
        module = assigns[:view_module]
        action = action_name( conn )

        module.title( action )
    end
  catch
    x -> “Default Title"
  end
end

I put the try/catch in there because I don’t know if there’s a way to check if a function exists for a module?

1 Like
iex(1)> h function_exported?

                def function_exported?(module, function, arity)                 

  @spec function_exported?(module(), atom(), arity()) :: boolean()

Returns true if module is loaded and contains a public function with the given
arity, otherwise false.

Note that this function does not load the module in case it is not loaded.
Check Code.ensure_loaded/1 for more information.

Inlined by the compiler.

## Examples

    iex> function_exported?(Enum, :member?, 2)
    true

:slight_smile:

2 Likes

Sweet, thanks!

1 Like

For anyone looking how to add page titles to both LiveViews and regular views, here is a code example using @OvermindDL1’s suggestion:

Include this in your html header:

<title>
  <%= title(@conn, assigns) %>
</title>

Next, include the following in your layout_view.ex file:

def title(conn, assigns) do
  cond do
    function_exported?(assigns[:live_view_module], :title, 1) ->
      apply(assigns[:live_view_module], :title, [assigns])

    function_exported?(assigns[:view_module], :title, 2) ->
      action = action_name(conn)
      apply(assigns[:view_module], :title, [action, assigns])
      
    true -> "Default title"
  end
end

You can then use a title/1 function in your LiveView and a title/2 function in your regular views.

4 Likes

Thanks @khedaywi.

This approach appears to work ok for liveviews rendered via the router, but I have just tested and unfortunately it doesn’t work if you live_link from one liveview to another because app.html.eex doesn’t get re-rendered. Also, if you want to update the title based on a parameter passed to the liveview, it won’t work either - the handle_params doesn’t update anything that is in scope when title gets called.

I’m not sure that there is a clean solution at this stage. A couple of ugly hacks come to mind, but the least hacky I can think of is to create a hidden element in the liveview with the title and use a javascript hook to update the document title on mount & update.

2 Likes

Agreed, I should have prefaced that this code works for traditionally rendered views and LiveViews rendered via a router, at least initially.

If you’re using LiveView within traditional views then it wouldn’t work. As you mentioned, you’d have to handle it with js hooks to update the title of the page as it’s likely not included in the full LiveView template.

3 Likes

For now appears we have to use JS hooks to set page title when using live_link but it was recently mentioned that they are planning to add support for layouts to LiveViews in the future. Presumably at that point we won’t need to use JS for this.

4 Likes