How does :if heex attribute work?

If you take a look at the form component generated by mix phx.gen.live, it sets a @page_title assign instead of handling the conditional logic in the heex template.

If you want to keep it in the template, here are some other options:

# `if/2` with a one liner keyword list, balances clarity and conciseness, my pick of the bunch
<h1>{if @category_id, do: gettext("Edit Category"), else: gettext("New Category")}</h1>
# pseudo-ternary, very concise but arguably too clever, also unexpected gotcha if middle bit is false-y when conditional is truth-y 
<h1>{@category_id && gettext("Edit Category") || gettext("New Category")}</h1>
# not my personal preference, but for the sake of completeness 
<h1 :if={@category_id}>{gettext("Edit Category")}</h1>
<h1 :if={@category_id == nil}>{gettext("New Category")}</h1> # or
<h1 :if={is_nil(@category_id)}>{gettext("New Category")}</h1> # or
<h1 :if={!@category_id}>{gettext("New Category")}</h1>
1 Like

Hi @codeanpeace

Unfortunately

<h1>{if @category_id, do: gettext("Edit Category"), else: gettext("New Category")}</h1>

is an invalid code.
I get a compilation error:

Compiling 1 file (.ex)

** (Phoenix.LiveView.Tokenizer.ParseError) lib/helpcenter_web/live/categories/category_form.ex:45:93: expected attribute name
    (phoenix_live_view 1.0.4) lib/phoenix_live_view/tokenizer.ex:744: Phoenix.LiveView.Tokenizer.raise_syntax_error!/3
    (phoenix_live_view 1.0.4) lib/phoenix_live_view/tag_engine.ex:300: Phoenix.LiveView.TagEngine.handle_text/3
    (eex 1.18.1) lib/eex/compiler.ex:331: EEx.Compiler.generate_buffer/4
    (phoenix_live_view 1.0.4) expanding macro: Phoenix.Component.sigil_H/2
    (helpcenter 0.1.0) lib/helpcenter_web/live/categories/category_form.ex:32: HelpcenterWeb.Categories.CategoryForm.render/1

Can you tell me what’s the problem?
Heiko

Hey @Chrichton,

the code should you quoted should work. At least i dropped it in a heex template and it worked right away. The error message implies that you are missing a name attribute on your form or input.
If you can’t figure out the issue, could you give us the full code of the form you’re trying to implement?

Hi Kevin.

I inserted the code again and now it works.
Please don’t ask me, why it didn’t work before
 :innocent:

Generally I do find it irritating, that there is the old style and the new style:

<!-- old style -->
<%= @something %>

<!-- new style -->
{@something}`

and both still do work.

I want to use the new style.

The old style for if else would be

 <%= if @category_id do %>
   {gettext("Edit Category")}
 <% else %>
   {gettext("New Category")}
 <% end %>

So

{if @category_id, do: gettext("Edit Category"), else: gettext("New Category")}

is just the new style using the expression

if, do: else:

right?

While moving to single line if works, the “old style” is still the way to go for cases where the single line if doesn’t work.

The difference would be that the new syntax with the inline if works only if you want to interpolate a value. The block syntax has the added benefit, that you can write additional HTML like this for example.

<%= if @category_id do %>
   <span class="text-blue-400">{gettext("Edit Category")}</span>
 <% else %>
   <span class="text-red-600">{gettext("New Category")}<span>
 <% end %>

This wouldn’t work when you write it like this:

{if @category_id, do: "<span class=\"text-blue-400\">#{gettext("Edit Category")}</span>", else: "<span class=\"text-red-600\">#{gettext("New Category")}<span>"}

As you can see, you would have to write it as a string and then it wouldn’t be handled as HTML