Passing dynamic value to html tag using component slots and attrs (v1.7.2)

I’m using Phoenix v1.7.2. I’m using the default index.html.heex for listing records.

My records have a ‘color’ field that I store as a default color. I would like to pass this value to the individual as a background color.

I’ve added this to the table component.

  slot :col, required: true do
    attr :label, :string
    attr :col_class, :string  ## My addition
  end
... and the table template looks like this

<tr :for={row <- @rows} id={@row_id && @row_id.(row)} class="group hover:bg-zinc-50">
  <td
      :for={{col, i} <- Enum.with_index(@col)}
      phx-click={@row_click && @row_click.(row)}
      class={["relative p-0", @row_click && "hover:cursor-pointer", col[:col_class]] <-My edit
  >
...

Here is the snippet of the table that I’m trying to modify. Static value works as below

<.table
  id="services"
  rows={@streams.services}
  row_click={fn {_id, service} -> JS.navigate(~p"/services/#{service}") end}
>
  <:col :let={{_id, service}} label="Name"><%= service.name %></:col>
  <:col :let={{_id, service}} label="Color" col_class="bg-slate-200"><%= service.color %></:col>  <- Works

But, I would like to do something like this

  <:col :let={{_id, service}} label="Color"  col_class={"bg-#{service.color}-200"><%= service.color %></:col>

but I’m getting this error

undefined function service/0 (expected HelloWeb.ServiceLive.Index to define such a function or for it to be imported, but none are available)

Thanks for looking at this

1 Like

The :let applies to the body of the tag but not its attributes. In other words, you can’t access the variables you defined on :let on the attributes themselves.

I think you can set a global attribute with a default class and then use that on the td.

The documentation includes an example with a default class value set.

https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#module-global-attributes

Man this is confusing! :blush: Any hint on how I can access the variable in the attributes? I apologize if it’s simple, but I’m still wrapping my head around consuming streams, components and heex.

I think this example fits best:

attr :rest, :global, default: %{class: “bg-blue-200”}

attr :message, :string, required: true

def notification(assigns) do
~H"“”
<span {@rest}><%= @message %>
“”"
end

You can‘t. :let={} is calculated by calling the function component, which passes in all other attributes. So all other attributes need to already exist and that before the value for :let={} is calculated. You‘d need to solve that within a single component/template.

3 Likes

Thanks for clarifying that. I started having assumptions this was the case. Now I can rest