How to handle "status" variables in a template comprehension

I imagine there is an easy way to accomplish this… I am attempting to do something like the below:

<% current_production_date = nil %>
<%= for widget <- @widgets do %>
  <%= if (current_production_date != widget.production_date) do %>
    <!-- ... output a new date header and re-assign current production_date -->
    <% current_production_date = widget.production_date %>
  <% end %>
  <%= render "_widget.html", widget: widget %>
<% end %>

This won’t work as you can’t rebind the “current_production_date” variable outside of the comprehension… but this seems like a pretty common scenario, so I’m guessing there’s probably a straight-forward way of accomplishing something like the above… I just can’t figure out how… any advice much appreciated!

Could you use Enum.reduce here instead and store your temp state in the accumulator?

Not sure where this ranks in best practises but it’s something I’ve used before.


Can’t you use Enum.group_by/2?


Thanks for the suggestions! I got things working with group_by/2. It is a little messy as I also needed to sort the resulting map but it seems to do the trick.

I ended up with something similar to:

<%= for {date, widgets}
  <- Enum.group_by(@widgets, fn(x) -> DateTime.to_date(x.production_date) end)
  |> Enum.sort(fn({date1, widget1}, {date2, widget2}) ->
    case, date1) do
      :lt -> true
      _ -> false
  end) do %>
  <%= render "_date_header.html", date: date %>
  <%= for widget <- widgets do  %>
    <%= render "_widget.html", widget: widget %>
  <% end %>
<% end %>

Well, the list had to be sorted already in your other use case.

But to be honest, I’d do the grouping and sorting in the controller or the view, not the template.


Yeah, that makes sense, the way I have it now the template is pretty nasty, I’ll move this out… thanks again!

1 Like