How to create lists in EEx templates
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.
Directory structure
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.
Setting up the route
Routing is necessary to render different application parts based on the
Navigate to the
lib/todo_app_web/router.exfile.Inside the
scopecode block, under thepipe_through :browserstatement, 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.
Building the live module
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
Code explanation
Lines 1–2: We define the module named
TodoAppWeb.TodoListsince it is in thetodo_app_web/livedirectory. Theusestatement configures the module to be compatible with the LiveView process.Line 4: We use the
mountfunction to define the initial state of the LiveView process when the user first visits its route. Themountfunction takes three arguments as input.paramsis a map containing the URL query parameters, andsessionis 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 thesocketargument, 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
assignfunction, we initialize the two states as a key/value pair and store them in thesocketstruct. Theitemstate will store the current todo item, and thetodosstate will store all of the todos.Line 10: We return the
socketstruct to keep it updated.Lines 13–17: We use the
handle_eventfunction to update the state in a LiveView process. It takes the name of the event, the metadata of the event, and thesocketstruct as an argument. The abovehandle_eventfunction defines theadd_todoevent and retrieves the new to-do item value from the form.Line 18: We update our
todosarray state inside the function by concatenating it with the new to-do item.Lines 20–25: Finally, we update the states in the
socketstruct by updating them with the latest values and returning the updatedsocketstruct.
Designing the view
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>
Code explanation
Line 1: We make a form element and attach the
add_todoevent 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
itemand the value corresponding to our stateitemin thesocketstruct, written as Elixir code inside the<%= %>tag.Line 8: We also add a button input named
Add itemwith asubmitevent for the user to click to add a to-do item.Lines 12–15: Finally, we add a
listelement to display all the todos. We make an Elixirforloop inside the<%= %>tag to iterate over each to-do item in thetodosarray and generate a list element containing the name of the to-do item.
Working example
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')
);
Best practices
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_fileandCode.eval_stringfunctions that can execute code dynamically.
Free Resources