Source code on GitHub
Phoenix makes rendering partial templates - or partials - dead-simple.
In this episode we’ll extract two different pieces of our template into partial templates that different templates can easily render.
Let’s get started.
Here we’re listing all movies from our database.
If we look at the movie index template we’re looping through all our movies and rendering rendering data about each one.
Let’s take this part of our template and extract it into a partial.
We’ll create a
_movie.html.eex template in our same directory.
And in it we’ll copy over the part of template we want.
Now one change we’ll need to make is to our
movie variable. Since this is a new template we’ll need to access our movie with
@movie - the
@ is macro that will essentially convert
<tr> <td><%= @movie.title %></td> <td><%= @movie.summary %></td> <td><%= @movie.year %></td> <td class="text-right"> <%= link "Show", to: movie_path(@conn, :show, @movie), class: "btn btn-default btn-xs" %> <%= link "Edit", to: movie_path(@conn, :edit, @movie), class: "btn btn-default btn-xs" %> <%= link "Delete", to: movie_path(@conn, :delete, @movie), method: :delete, data: [confirm: "Are you sure?"], class: "btn btn-danger btn-xs" %> </td> </tr>
Now we can go back to our
index.html template and update our list comprehension to render our new template.
render, with the template we want to render, in this case our
_movie.html, and then our assigns, which will be our ‘movie’.
We’ll also include our connection since we’re accessing it in the template.
<%= for movie <- @movies do %> <%= render "_movie.html", movie: movie, conn: @conn %> <% end %>
Now let’s go to the browser and our movies are still be loaded correctly.
While this works, because we’re rendering a collection, let’s update it to use the
We’ll go back to our template and call
render_many which takes our collection, in this case our movies, our view of
MovieView, the template we want to render, and our assigns. In this case we only need to include our connection.
Then we can remove our list comprehension.
<%= render_many @movies, TeacherWeb.MovieView, "_movie.html", conn: @conn %>
Then let’s go back to the browser and great - every thing looks good.
Now if we look at the top of our page, we see the title of our app and some navigation links.
These should be displayed on all pages, but if we click on our ‘About’ link - we see they’re missing. Let’s fix that.
We’ll again open our
index.html.eex and at the top of the file is the piece we want to extract.
Now we could add a partial to our ‘layout’ directory and render it similar to how we did with our ‘movie’ partial, but let’s try a different approach and create it as a ‘shared’ template that many templates can access.
We’ll create a new directory in templates called ‘shared’ and inside it we’ll create our template
_header.html.eex and we’ll paste in our content.
<div class="nav-header"> <h1>Movie App</h1> <div class="nav-link"> <%= link "All Movies", to: movie_path(@conn, :index) %> <%= link "About", to: page_path(@conn, :about) %> </div> </div>
Now we’ll need to create a view. We’ll create a new file in ‘views’ called
shared_view.ex. Then let’s define our new view module.
defmodule TeacherWeb.SharedView do use Teacher.Web, :view end
With that let’s go to where we want to render this template - in this case our
And we’ll render our template here. Even though our template is in a different directory, we can still render it.
We’ll just call render, with the view module, the template we want to use, and the assigns.
<main role="main"> <%= render TeacherWeb.SharedView, "_header.html", assigns %> <%= render @view_module, @view_template, assigns %> </main>
Let’s go back to our browser and if we click through to different pages - we see our header content is being displayed on every page.