Shared templates between LiveView and static pages
2 min read
Ever wanted to share some templates between your LiveViews and other static pages? Footers/headers/sidebars and such parts of a website can be shared. Here is something to help you.
You can define a view like this:
defmodule YourAppWeb.SharedView do use YourAppWeb, :view end
and define some templates for it, like
lib/templates/shared/header.html.leex. Note the
leex extension, as this will be used by LiveViews too.
Now, you can render it as a normal view in your
<%= render YouAppWeb.SharedView, "header.html", assign1: value1 %>
You can define a function like this somewhere (and
import it in your
def render_shared(templates, assigns \\ ) do render(YouAppWeb.SharedView, template, assigns) end
and replace the render call with this:
<%= render_shared "header.html", assign1: value1 %>
And that's it. A normal view is rendered in your static pages.
Now for the LiveViews, you can use a LiveComponent to render this view. Define a LiveComponent like this:
defmodule YourAppWeb.Live.Header do use YourAppWeb, :live_component def render(assigns) do render_shared("header.html", assigns) end end
This way, LiveComponent renders the same view. Now, you can use it in your
live.html.leex like this:
<%= live_component @socket, YourAppWeb.Live.Header, assign1: value1 %>
And that's it. You have a view rendered in both your static and LiveView pages.
There are some things to note here about assigns. When rendering a static page, you have a
@conn that is a
Plug.Conn, and when rendering a LiveComponent you have a
@socket that is a
@socket.assigns may not be available at all. Don't rely on the whole assigns when rendering your view. Instead, explicitly pass everything you need:
# In `app.html.eex` <%= render_shared "header.html", current_user: @current_user %> # In `live.html.leex` <%= live_component @socket, YourAppWeb.Live.Header, current_user: @current_user %> # in `header.html.leex` <%= @current_user.name %>
Also, note that we're defining a stateless component. You can make your component stateful, but that would require some extra care in your view.
Bottom line is, this won't scale if your shared views are complex, with too much dynamicity. Keep them small, and mostly static, and this will help you DRY.