Cant figure out closing tag?

I have two problems in my code:

<button
  phx-click="select_horse"
  phx-value-horse_id="{horse.id}"
  {unless assigns.race_in_progress || assigns.race_ended || assigns.coins == 0, do: "", else: "disabled" }
  class="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md
    <%= if assigns.selected_horse_id == horse.id, do: "bg-blue-600 text-white animate-pulse", else: "bg-white text-gray-700 hover:bg-gray-100" %>
    mr-4 mb-4 <%= unless assigns.race_in_progress || assigns.race_ended || assigns.coins == 0, do: "", else: "opacity-50 cursor-not-allowed" %>"
>
  <%= horse.emoji %> <%= horse.name %>
</button>

here at <%= if assigns its saying:
Make sure the attribute is properly closed. This may also happen if
there is an EEx interpolation inside a tag, which is not supported.
Instead of

<div <%= @some_attributes %>>
</div>

do

<div {@some_attributes}>
</div>

Where @some_attributes must be a keyword list or a map.

|
73 | <% else %>
74 |

Leider verloren :confused:


75 | <% end %>
76 |
| ^

I tried what it suggests but its hard due to the “do:” I have there

I believe you can’t interpolate inside strings with HEEx, possibly intentionally, the following gives the same error:

<button data-test="abc <%= true %>" >
hi
</button>

With HEEx attr={false|nil} attributes are dropped, and attr={true} becomes attr="". You can also give a list of string|nil|false for class attributes and it will discard the nils & falsi.

So you can simplify your code to something like:

<button
  phx-click="select_horse"
  phx-value-horse_id="{horse.id}"
  disabled={race_in_progress || assigns.race_ended || assigns.coins == 0}
  class={[
    "inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md",
    if(assigns.selected_horse_id == horse.id,
      do: "bg-blue-600 text-white animate-pulse",
      else: "bg-white text-gray-700 hover:bg-gray-100"
    ),
    "mr-4 mb-4",
    unless(assigns.race_in_progress || assigns.race_ended || assigns.coins == 0,
      do: "",
      else: "opacity-50 cursor-not-allowed"
    )
  ]}
>
  <%= horse.emoji %> <%= horse.name %>
</button>

You need the brackets for the if so the compiler can tell what is part of the if expression and what is part of the surrounding list. I wrote it as (if x, do...) but the autoformatter suggests as show.

You can further simplify it with && and ||

<button
  phx-click="select_horse"
  phx-value-horse_id="{horse.id}"
  disabled={assigns.race_in_progress || assigns.race_ended || assigns.coins == 0}
  class={[
    "inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md",
    (assigns.selected_horse_id == horse.id &&
       "bg-blue-600 text-white animate-pulse") ||
      "bg-white text-gray-700 hover:bg-gray-100",
    "mr-4 mb-4",
    (assigns.race_in_progress || assigns.race_ended || assigns.coins == 0) &&
      "opacity-50 cursor-not-allowed"
  ]}
>
  <%= horse.emoji %> <%= horse.name %>
</button>

You also probably dont want to quote the horse id expression:


phx-value-horse_id={horse.id}

And you probably also want to replace assigns.x with @x.

2 Likes

You can’t have <%= %> anywhere inside tags. You need to do this:

<.button
  ...
  class={["inline-flex ...", if(@selected_horse_id == horse.id, do: "...", else: "...")]}
>

Also note: @selected_horse_id over assigns.selected_horse_id. It’s unrelated but you should avoid using assigns directly in heex templates as it breaks change tracking (I believe there are warnings for this now).

EDIT: Oops, did not see soup beat me to it :upside_down_face:

3 Likes