Raxx.View

Generate HTML views from .eex template files for Raxx web applications.

Hex pm License

Defining Views

Common layout to use in multiple views.

lib/my_app/layout.html.eex

<header>
  <h1><% title %></h1>
  <%= __content__ %>
</header>

Template to show a list of users.

lib/my_app/list_users.html.eex

<%= for user <- users do %>
<section>
  <a href="/users/<%= user.id %>"><%= user.name %></a>
  <p>
    Joined on <%= Timex.format!(user.registered_at, "{YYYY}-0{M}-0{D}") %>
  </p>
</section>

View module that uses our templates.

lib/my_app/list_users_view.ex

defmodule MyApp.ListUsersView do
  use Raxx.View,
    arguments: [:users],
    optional: [title: "My App"]
    template: "list_users.html.eex",
    layout: "layout.html.eex"
end
  • variables set in :optional have a default value that can be overwritten when using the view.
  • If :template is left unspecified the view will assume the template is in a file of the same name but with extension .html.eex in place of .ex or .exs.
  • An option for :layout can be omitted if all the content is in the view.
  • The :arguments can be set to [:assigns] if you prefer to use @var in you eex templates. This will not give you a compile time waring about unused arguments.

Using views

The Raxx.View macro generates a render function for adding a view to a request/response.

response = Raxx.response(:ok)
MyApp.ListUsersView.render(response, user, title: "Users Page")

To work directly with the generated string an html function is also generated.

MyApp.ListUsersView.html(user, title: "Users Page")

Views in controllers/actions

For simple usecases it is often more convenient to keep the controller and view code together.

defmodule MyApp.ListUsers do
  use Raxx.SimpleServer
  use Raxx.View,
    arguments: [:users],
    optional: [title: "My App"]
    template: "list_users.html.eex",
    layout: "layout.html.eex"

  @impl Raxx.SimpleServer
  def handle_request(_request, _state) do
    users = MyApp.fetch_users()

    response(:ok)
    |> render(users)
  end
end

Helpers

Helpers can be used to limit the amount of code written in a template. Functions defined in a view module, public or private, can be called in the template.

lib/my_app/list_users.ex

# ... rest of module

def display_date(datetime = %DateTime{}) do
  Timex.format!(datetime, "{YYYY}-0{M}-0{D}")
end

def user_page_link(user) do
  ~E"""
  <a href="/users/<%= user.id %>"><%= user.name %></a>
  """
end

Update the template to use the helpers.

lib/my_app/list_users.html.eex

<%= for user <- users do %>
<section>
  user_page_link(user)
  <p>
    Joined on <%= display_date(user.registered_at) %>
  </p>
</section>

Partials

A partial is like any another helper function, but one that uses an EEx template file.

lib/my_app/list_users.ex

# ... rest of module

partial(:profile_card, [:user], template: "profile_card.html.eex")
  • If :template is left unspecified the partial will assume the template is in a file with the same name as the partial with extension .html.eex.

Update the template to make use of the profile_card helper

lib/my_app/list_users.html.eex

<%= for user <- users do %>
profile_card(user)
<% end %>

Reusable Layouts and Helpers

Layouts can be used to define views that share layouts and possibly helpers.

lib/my_app/layout.ex

defmodule MyApp.Layout do
  use Raxx.View.Layout,
    layout: "layout.html.eex",
    optional: [title: "My App"]

  def display_date(datetime = %DateTime{}) do
    Timex.format!(datetime, "{YYYY}-0{M}-0{D}")
  end

  def user_page_link(user) do
    ~E"""
    <a href="/users/<%= user.id %>"><%= user.name %></a>
    """
  end

  partial(:profile_card, [:user], template: "profile_card.html.eex")
end
  • If :layout is left unspecified the layout will assume the template is in a file of the same name but with extension .html.eex in place of .ex or .exs.
  • All functions defined in a layout will be available in the derived views.

The list users view can be derived from our layout and use the shared helpers.

lib/my_app/list_users.ex

defmodule MyApp.ListUsersView do
  use MyApp.Layout,
    arguments: [:users],
    optional: [title: "List users - My App"]
    template: "list_users.html.eex",
end
  • Variables set in :optionals for the layout can have there default value overwritten by setting them again when using the layout.