How to pipe assigns in LiveView component

Background

I have Phoenix LiveView core component that I created that has a few attributes: circumference, hidden, offset and class.

The main attributes I care about for this issue are hidden and class, since hidden can affect the value of class, i.e., it will show it or not.

Code

To achieve this I am trying the following code which does not work:

def progress_bar(assigns) do
    assigns = assign(assigns, :circumference, 2 * 22 / 7 * 120)

    assigns =
      assign(
        assigns,
        offset: assigns.circumference - assigns.progress / 100 * assigns.circumference,
        class: if assigns.hidden do "hidden" else assigns.class end
      )

    ~H"""
    <div class={@class}>
          <p> some test </p>
    </div>
    """
  end

Using this code, the <p> is never shown, even when @hidden is false. This was puzzeling me so I changed the code to the following version which does work:

def progress_bar(assigns) do
    assigns = assign(assigns, :circumference, 2 * 22 / 7 * 120)

    assigns =
      assign(
        assigns,
        :offset, 
        assigns.circumference - assigns.progress / 100 * assigns.circumference
      )

    ~H"""
    <div class={[@class, if @hidden do "hidden" end]}>
          <p> some test </p>
    </div>
    """
  end

Questions

The problem here is that even though the code appears the same, I dont understand why the second version works. Normally then, I have some questions:

  • Why does the second version work?
  • Is there a way to remove the if statement and assign it to class so the code is cleaner?
1 Like

What is the HTML output of the first version? I assume it always has “hidden”.

You can do:
‘<div class={[@class, @hidden && “hidden”]}>’

1 Like

with this code:

  assigns = assign(assigns, :circumference, 2 * 22 / 7 * 120)

    IO.inspect(assigns.class, label: "CLASS 1")

    assigns =
      assign(
        assigns,
        offset: assigns.circumference - assigns.progress / 100 * assigns.circumference,
        class: if assigns.hidden do "hidden" else assigns.class end
      )

    IO.inspect(assigns.class, label: "CLASS 2")

  ~H"""
    <div class={@class}>
          <p> some test </p>
    </div>
    """

The output is:

10:10:01.247 [info] updating page
CLASS 1: "flex items-center justify-center h-screen"
CLASS 2: "flex items-center justify-center h-screen"

Which means that @class does have the correct value.

Yeah but when you view the page in your browser and inspect the generated HTML, how does it look?

You said in the first case the p tag is never shown but the classes seems correct (without hidden).

Do you have the attr definitions for your component?

But ultimately you don’t need the if statement to change the @class, the other comment shows a clean way to conditionally add classes to the HTML based on an assign value.


Pasting it here again because I wrote on my phone and I can’t update the post anymore to add the code block.

<div class={[@class, @hidden && "hidden"]}>

For reasons beyond me, I think the reason @class was not showing was because of other interactions with other classes.

On another note:

<div class={[@class, @hidden && "hidden"]}>

This did work!

As a consequence I no longer need to change @class on the go.