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 app.html.eex
:
<%= render YouAppWeb.SharedView, "header.html", assign1: value1 %>
You can define a function like this somewhere (and import
it in your my_app_web.ex
in view_helpers
function):
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 Phoniex.LiveView.Socket
. Also, @conn.assigns
and @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.