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
def title(_action, _assigns), do: "Tasks"
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.
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>
LayoutView, this is what the
title function looks like:
def title(conn, assigns) do
assigns |> Map.has_key?(:live_view_module) ->
module = assigns[:live_view_module]
assigns |> Map.has_key?(:view_module) ->
module = assigns[:view_module]
action = action_name( conn )
module.title( action )
x -> “Default Title"
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?
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.
iex> function_exported?(Enum, :member?, 2)
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(@conn, assigns) %>
Next, include the following in your
def title(conn, assigns) 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"
You can then use a
title/1 function in your LiveView and a
title/2 function in your regular views.
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.
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.
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.