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.

widget

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 URLUniform Resource Locator path. We’ll be rendering our to-do application on the root path of the application. To set a route, we’ll perform the following steps.

  1. Navigate to the lib/todo_app_web/router.ex file.

  2. 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.

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 do
use TodoAppWeb, :live_view
def mount(_params, _session, socket) do
socket =
socket
|> assign(:item, "")
|> assign(:todos, [])
{:ok, socket}
end
def handle_event(
"add_todo",
%{"item" => item},
socket
) do
news=socket.assigns.todos++[item]
socket =
socket
|> assign(:item, "")
|> assign(:todos, news)
{:noreply, socket}
end
end

Code explanation

  • 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.

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_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.

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')
);
Working example of building lists in EEx templates

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_file and Code.eval_string functions that can execute code dynamically.

Copyright ©2024 Educative, Inc. All rights reserved