EEx stands for Embedded Elixir. EEx templates enable us to embed Elixir code inside strings. EEx templates are HTML markups where we can add Elixir code along with HTML to produce dynamic functionality in the code. These templates are precompiled, which makes them highly performant in web applications.
EEx templates are used in Phoenix, an Elixir framework, to build interactive web applications. In this Educative Answer, we’ll learn how to create lists in EEx templates by building a basic to-do application in Phoenix. The to-do application will consist of a form with text input and a submit button so that the user can add to-dos. Additionally, all of the to-dos will be listed on the web page.
The directory structure of the Phoenix application named ”todo_app” is as follows:
todo_app/├── assets├── config└── lib/└── todo_app/└── todo_app_web/├── components├── controller├── live├── endpoint.ex├── router.ex├── gettext.ex└── telemetry.ex
We’ll work mainly with the lib/todo_app_web/router.ex
file and the lib/todo_app_web/live
folder. The live
here implies that we’ll use the Phoenix LiveView programming model that efficiently renders state updates to a Phoenix application.
Routing is necessary to render different application parts based on the
Navigate to the lib/todo_app_web/router.ex
file.
Inside the scope
code block, under the pipe_through :browser
statement, define the route as follows:
live "/", TodoList
The live
macro takes the path and the name of the controller module as an argument. The above syntax defines a route at the root path that the TodoList
live module will handle.
We create a new file named todo_app_web/live/todo_list.ex
. It’s an important file convention in the Phoenix framework to name the file similar to the module’s name. We create the module as follows:
defmodule TodoAppWeb.TodoList douse TodoAppWeb, :live_viewdef mount(_params, _session, socket) dosocket =socket|> assign(:item, "")|> assign(:todos, []){:ok, socket}enddef handle_event("add_todo",%{"item" => item},socket) donews=socket.assigns.todos++[item]socket =socket|> assign(:item, "")|> assign(:todos, news){:noreply, socket}endend
Lines 1–2: We define the module named TodoAppWeb.TodoList
since it is in the todo_app_web/live
directory. The use
statement configures the module to be compatible with the LiveView process.
Line 4: We use the mount
function to define the initial state of the LiveView process when the user first visits its route. The mount
function takes three arguments as input. params
is a map containing the URL query parameters, and session
is a map containing the private session data. Both arguments are preceded by _
because we won’t use them in the function. We’ll only deal with the socket
argument, a struct containing all the state of the current LiveView process.
Lines 5–8: Because we’re building a todo application, we need to store the state of the current to-do item as a string and the state of all todos as an array. Using the assign
function, we initialize the two states as a key/value pair and store them in the socket
struct. The item
state will store the current todo item, and the todos
state will store all of the todos.
Line 10: We return the socket
struct to keep it updated.
Lines 13–17: We use the handle_event
function to update the state in a LiveView process. It takes the name of the event, the metadata of the event, and the socket
struct as an argument. The above handle_event
function defines the add_todo
event and retrieves the new to-do item value from the form.
Line 18: We update our todos
array state inside the function by concatenating it with the new to-do item.
Lines 20–25: Finally, we update the states in the socket
struct by updating them with the latest values and returning the updated socket
struct.
The last step is to create a view that will be rendered on the web page when the user visits our route. We’ll create a todo_app_web/live/todo_list.html.leex
file where we can add Elixir functionality inside an HTML template with the following code:
<form phx-submit="add_todo"><fieldset><label for="nameField">Enter an item</label><input type="text" name="item" value="<%= @item %>"placeholder="Go for a walk"autofocus autocomplete="off" /><input class="button-primary" type="submit" value="Add item"></fieldset></form><ul class="list"><%= for todo <- @todos do %><li><%= todo %></li><% end %></ul>
Line 1: We make a form element and attach the add_todo
event handler to the form submit event.
Lines 4–7: We add a text input element for the user to insert todos. It has the name item
and the value corresponding to our state item
in the socket
struct, written as Elixir code inside the <%= %>
tag.
Line 8: We also add a button input named Add item
with a submit
event for the user to click to add a to-do item.
Lines 12–15: Finally, we add a list
element to display all the todos. We make an Elixir for
loop inside the <%= %>
tag to iterate over each to-do item in the todos
array and generate a list element containing the name of the to-do item.
Here’s a final working example of the todo application. Click the “Run” button to start the application. After the server starts, visit the link below the “Run” button to view the application. In the application, you can add various to-do items, which will be updated dynamically.
import React from 'react'; require('./style.css'); import ReactDOM from 'react-dom'; import App from './app.js'; ReactDOM.render( <App />, document.getElementById('root') );
When deploying the application, it’s not recommended to deploy the development version. Instead, deploy the optimized build version for fast performance.
Since EEx templates contain dynamic code, they’re susceptible to harmful code injection attacks, where dangerous code is injected into the templates to harm the user’s system. Therefore, it’s recommended to avoid the use of Code.eval_file
and Code.eval_string
functions that can execute code dynamically.