The simplest option would be to pass the page title along with the render call in your controller action. For example you could do
render(conn, “new.html”, page_title: “New Resource”). Then, in your app layout template
app.html.eex, access it with
<title><%= @page_title %></title>.
The problem with this approach is that you have to provide the page_title for every controller action. In addition setting the page title should probably be done by the view and not the controller. Here is how you’d do that.
Start out by adding phoenix controller’s
action_name/1 to the imported helpers for our view in web.ex. action_name/1 returns the action as atom that is being performed for the current conn (:new, :create, :update, …).
# web/web.ex def view do # Import convenience functions from controllers import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1, action_name: 1] ... end
Next up create a
title/2 function in our
LayoutView module. This function will try and ask the view module being rendered for its title or return a default title instead.
# web/views/layout_view.ex @doc """ Calls the `title` fun of the current `view_module` with the performed `:action` as arg. If no fun exists/matches the `default` title is returned instead. """ def title(conn, default) do try do apply(view_module(conn), :title, [action_name(conn)]) rescue _ -> default end end
view_module(conn) we fetch the module of the view which is being rendered, for example the UserView.
apply/3 will try to call the function
:title inside that module with the action name as argument.
If that view does not implement
UndefinedFunctionError error is thrown. We don’t really care about the kind of the error so in our rescue block we just return the default title instead.
Now it is time to implement the
title/1 function in all views we want to specify a custom title for. In this example I assume you have a user model with matching user controller and a user view.
# web/views/user_view.ex def title(:index), do: "List all users" def title(:new), do: "Create a new user" def title(:show), do: "Show a single user" def title(_), do: "Users"
We use elixir’s pattern matching to specify a custom title for every controller action. If you only need one title for all actions simply use
def title(_), which will always match.
That’s it. Open the layout template at
web/templates/layout/app.html.eex and add the call to
# web/templates/layout/app.html.eex <head> ... <title><%= title @conn, "My Default Title" %></title> ... </head>
title @conn, “My Default Title” will call
title/2 defined in our
web/views/layout_view.ex, which in turn via
apply/3 calls the
title/1 function of the current view module that is being rendered. If no function matches or none is found “My Default Title” is used instead.