Phoenix.View
Defines the view layer of a Phoenix application.
This module is used to define the application main view, which serves as the base for all other views and templates in the application.
The view layer also contains conveniences for rendering templates, including support for layouts and encoders per format.
Examples
Phoenix defines the main view module at /web/view.ex:
defmodule YourApp.View do
use Phoenix.View, root: "web/templates"
# The quoted expression returned by this block is applied
# to this module and all other views that use this module.
using do
quote do
# Import common functionality
import YourApp.I18n
import YourApp.Router.Helpers
# Use Phoenix.HTML to import all HTML functions (forms, tags, etc)
use Phoenix.HTML
end
end
# Functions defined here are available to all other views/templates
end
We can use the main view module to define other view modules:
defmodule YourApp.UserView do
use YourApp.View
end
Because we have defined the template root to be “web/template”, Phoenix.View
will automatically load all templates at “web/template/user” and include them
in the YourApp.UserView
. For example, imagine we have the template:
# web/templates/user/index.html.eex
Hello <%= @name %>
The .eex
extension is called a template engine which tells Phoenix how
to compile the code in the file into actual Elixir source code. After it is
compiled, the template can be rendered as:
Phoenix.View.render(YourApp.UserView, "index.html", name: "John Doe")
#=> {:safe, "Hello John Doe"}
We will discuss rendering in detail next.
Rendering
The main responsibility of a view is to render a template.
A template has a name, which also contains a format. For example, in the previous section we have rendered the “index.html” template:
Phoenix.View.render(YourApp.UserView, "index.html", name: "John Doe")
#=> {:safe, "Hello John Doe"}
When a view renders a template, the result returned is an inner
representation specific to the template format. In the example above,
we got: {:safe, "Hello John Doe"}
. The safe tuple annotates that our
template is safe and that we don’t need to escape its contents because
all data was already encoded so far. Let’s try to inject custom code:
Phoenix.View.render(YourApp.UserView, "index.html", name: "John<br />Doe")
#=> {:safe, "Hello John<br />Doe"}
This inner representation allows us to render and compose templates easily.
For example, if you want to render JSON data, we could do so by adding a
“show.json” entry to render/2
in our view:
defmodule YourApp.UserView do
use YourApp.View
def render("show.json", %{user: user}) do
%{name: user.name, address: user.address}
end
end
Notice that in order to render JSON data, we don’t need to explicitly return a JSON string! Instead, we just return data that is encodable to JSON.
Both JSON and HTML formats will be encoded only when passing the data
to the controller via the render_to_iodata/3
function. The
render_to_iodata/3
uses the notion of format encoders to convert a
particular format to its string/iodata representation.
Phoenix ships with some template engines and format encoders, which
can be further configured in the Phoenix application. You can read
more about format encoders in Phoenix.Template
documentation.
Summary↑
__using__(options) | When used, defines the current module as a main view module |
render(module, template, assigns) | Renders a template |
render_to_iodata(module, template, assign) | Renders the template and returns iodata |
render_to_string(module, template, assign) | Renders the template and returns a string |
using(list1) | Implements the |
Functions
Renders a template.
It expects the view module, the template as a string, and a set of assigns.
Notice this function returns the inner representation of a
template. If you want the encoded template as a result, use
render_to_iodata/3
instead.
Examples
Phoenix.View.render(YourApp.UserView, "index.html", name: "John Doe")
#=> {:safe, "Hello John Doe"}
Assigns
Assigns are meant to be user data that will be available in templates. However there are keys under assigns that are specially handled by Phoenix, they are:
:layout
- tells Phoenix to wrap the rendered result in the given layout. See next section.
Layouts
Template can be rendered within other templates using the :layout
option. :layout
accepts a tuple of the form
{LayoutModule, "template.extension"}
.
When a template is rendered, the layout template will have an @inner
assign containing the rendered contents of the sub-template. For HTML
templates, @inner
will be always marked as safe.
Phoenix.View.render(YourApp.UserView, "index.html",
layout: {YourApp.LayoutView, "application.html"})
#=> {:safe, "<html><h1>Hello!</h1></html>"}
Renders the template and returns iodata.
Renders the template and returns a string.
Macros
When used, defines the current module as a main view module.
Options
:root
- the template root to find templates:namespace
- the namespace to consider when calculating view paths
The :root
option is required while the :namespace
always to the
first nesting in the module name. For instance, both MyApp.UserView
and MyApp.Admin.UserView
have namespace MyApp
.
The namespace is used to calculate paths. For example, if you are in
MyApp.UserView
and the namespace is MyApp
, templates are expected
at Path.join(root, "user")
. On the other hand, if the view is
MyApp.Admin.UserView
, the path will be Path.join(root, "admin/user")
and so on.
Setting the namespace to MyApp.Admin
in the second example will force
the template to also be looked up at Path.join(root, "user")
.
Implements the __using__/1
callback for this view.
This macro expects a block that will be executed every time the current module is used, including the current module itself. The block must return a quoted expression that will then be injected on the using module. For example, the following code:
defmodule MyApp.View do
use Phoenix.View, root: "web/templates"
using do
quote do
IO.inspect __MODULE__
end
end
end
defmodule MyApp.UserView do
use MyApp.View
end
will print both MyApp.View
and MyApp.UserView
names. By using
MyApp.View
, MyApp.UserView
will automatically be made a view
too.