fireproofsocks
Complex loop in EEx
I’m trying to build a loop in an EEx template that may have to iterate over a list OR a map (i.e. loop over its keys/values) and include an index (yes, I know that’s a lot).
So far, my EEx template looks like this:
The start...
<%= Enum.with_index(list)
|> Enum.map(fn {x, index} ->
case x do
{k, v} -> %>
<%= k %> <%= v %>: @index: <%= index %>
<% x -> %>
<%= x %>: @index: <%= index %>
<% end %>
<% end) %>
...The end.
But that results in an error:
** (TokenMissingError) nofile:12: missing terminator: end (for "fn" starting at line 3)
lib/eex/compiler.ex:101: EEx.Compiler.generate_buffer/4
lib/eex/compiler.ex:54: EEx.Compiler.generate_buffer/4
lib/eex.ex:199: EEx.eval_string/3
my_file.exs:37: (file)
A simpler EEx template works:
The start...
<%= Enum.with_index(list)
|> Enum.map(fn {x, index} -> %>
<%= x %>: @index: <%= index %>
<% end) %>
...The end.
but that one only handles lists. I think I’m getting stuck on where exactly I’m allowed to break in and out of Elixir code within an EEx template. The basic logic works when it’s not in EEx.
Thanks for any pointers!
Most Liked
patrickdm
Hello, I’d try to simplify it by moving the function to the view module, using string interpolation, i.e. (disclaimer: untested code ahead…)
def eval_item(x, index) do
case x do
{k, v} ->
"#{k} #{v} : @index: #{index}"
val ->
"#{val} : @index: #{index}"
end
end
or with two functions using pattern matching on arguments (that I prefer as I find it easier to read):
def eval_item({k, v} = x, index), do: "#{k} #{v} : @index: #{index}"
def eval_item(x, index), do: "#{x} : @index: #{index}"
then in the template you could just:
<%= Enum.with_index(list) |> Enum.map(&eval_item/2) %>
hth.
kokolegorille
I would even go further and put all logic in a helper function. Putting logic in the template is not something I would advise.
Somehing like
<%= do_something(list) %>
patrickdm
yes, good advice! 
[…edit…] Putting all together would look like:
in template.html.eex
<%= iterate_over(list) %>
in template_view.ex
def iterate_over(list) do
list
|> Enum.with_index()
|> Enum.map(&eval_item/2)
end
defp eval_item({k, v} = _x, index), do: "#{k} #{v} : @index: #{index}"
defp eval_item(x, index), do: "#{x} : @index: #{index}"
Ninigi
<% %> doesn’t work like that (been there tried that
), and you can simplify the map/case by pattern matching in the function signatures.
untested:
<%= Enum.with_index(list) |> Enum.map(fn
{{k, v}, index} ->
"#{k} #{v}: @index: #{index}"
{x, index} ->
"#{x}: @index: #{index}"
end) %>







