Is there an "else" to :if syntax in Heex templates?

Asking to get a sense of what other people are doing with their template logic…

The template code

I’m reading some third-party template code like this:

      <li :if={message.role == :function_call} class="...">
        ...
              <.icon_for_role role={message.role} />
       ...
      </li>
      <li :if={message.role != :function_call} class="...">
        ...
              <.icon_for_role role={message.role} />
        ...
            <.markdown :if={message.role == :assistant} text={message.content} />
            <span :if={message.role != :assistant} >
              ...
            </span>
        ...
      </li>

In more than one occasion there’s a tag with an :if attribute immediately followed by a sibling tag with another :if that is the negation of the previous condition.

I realized a casual search of the docs for :if (Search for terms beginning with colon (e.g. ":if") · Issue #1820 · elixir-lang/ex_doc · GitHub) doesn’t work, but nonetheless found Components and HEEx — Phoenix v1.7.10. Docs and local code searches suggest there’s only :if and :for, no :else.

I wonder what other people are doing for cases like that? Repeating+negating conditions feels error prone to me.

How I think it should be written

I think <%= if %> ... <% else %> ... <% end %> would be more appropriate for template code like above? Or even <%= case %> and <%= cond %> for the more general cases?

I know JS frameworks like Vue have <tag v-if="condition">...</tag><tag v-else>...</tag>, but would not propose making Heex have even more ways to accomplish things that are already possible with existing syntax :smile:

What do you normally do in cases like that?

1 Like

Edit: didn’t notice that you were talking about :if

1 Like

I just got an idea. Why not create one’s own component named if or so.
It could be used like below.

<.if true={true}>
  This is true!
  <:else>
    That's false!
  </:else>
</.if>

So basically we have the if component which has a true attribute to check a condition and an else slot to render something when the condition passed to true won’t met. Otherwise the content in the inner_block will be the one to be rendered.

I don’t think an :else would make sense in heex syntax since it would be ambigous which clause it applied to.

But, what about :unless={} ?

Still, which previous :if would this :unless correspond to? I ask because I think what the OP is looking for is a way of not having to check a condition when a previous tag has already checked the negation of that same condition.

Then perhaps you’re saying that any :unless that follows a :if at the same nesting level should be considered the negation of that :if? In that case, the :unless wouldn’t even need to specify a condition.

An improved version could be as follows. The only drawback would be to have to define a component for every tag we want to apply this to.

<.li cond={true}>
  This is true!
  <:unless>
    That's false!
  </:unless>
</.li>

:unless={condition} would be a short hand for :if={!condition} , no previous clause needed. I’m only suggesting it because elixir already has it: Kernel — Elixir v1.16.0-rc.0 (just not in heex).

1 Like

Thanks for the clarification.

Personally I don’t think it will add anything, except perhaps aesthetics for those who like this form.

I suppose that :if or :unless thing is actually more for checking that a condition is met without worrying about what happens if it’s not.

If we want to do something more complex, I think we can simply use <%= if %> ... <% else %> ... <% end %> as suggested by the OP. ^^

1 Like

Thanks for the replies!

Yeah, I’m just more certain I would not like to learn more syntax (and inflict the same learning on everyone else) and have so many ways to accomplish the same things :smile:

1 Like