Pass data to render_slot

I want to pass @parent_id to render_slot. But I am unable to find in assigns of inner_block. What am i missing?

def accordion(assigns) do
    assigns = 
      assigns
      |> create_id("acc")
      |> add_class("accordion")
      |> add_class_if_present(:flush, "flush")
    
    assigns = assign(assigns, :data, %{parent_id: assigns[:id]})
    require Logger
    Logger.info("accordion assigns = #{inspect assigns}")
    ~H"""
    <div class={@class} id={@id} >
      <%= render_slot(@inner_block, @data) %>
    </div>
    """
  end

def accordion_item(assigns) do
    require Logger
    Logger.info("assigns = #{inspect assigns}")
    Logger.info("@###@")
    assigns = 
      assigns
      |> create_id("aci")
      |> add_class("accordion")
      |> add_class_if_present(:flush, "flush")
      |> create_id(:header_id, "ach")
      |> assign_if_present(:show, "show", "")

    ~H"""
     <div class="accordion-item">
      <h2 class="accordion-header" id={@header_id}>
        <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target={"##{@id}"} aria-expanded="true" aria-controls={@id}>
          <%= render_slot(@header) %>
        </button>
      </h2>
      <div id={@id} class={"accordion-collapse collapse #{@show}"} aria-labelledby="headingOne" data-bs-parent={"##{@parent_id}"}>
        <div class="accordion-body">
          <%= render_slot(@body) %>
        </div>
      </div>
    </div>
    """
  end

<.accordion>
    <.accordion_item show>
      <:header>
        Accordion Item #1
      </:header>
      <:body>
        <strong>This is the first item's accordion body.</strong> It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
      </:body>
    </.accordion_item>
  </.accordion>

1 Like

Any help or thoughts on this ?

Hey @kartheek, have a look at the docs. Particularly the table example under the link I’ve provided.

You can pass data to the slot as the second argument of render_slot and bind it to a name using the let argument.


For a table component like this:

<.table rows={@users}>
  <:col let={user} label="Name">
    <%= user.name %>
  </:col>

  <:col let={user} label="Address">
    <%= user.address %>
  </:col>
</.table>

Loop over the rows and for each col, pass in the user as row

...
    <%= for row <- @rows do %>
      <tr>
        <%= for col <- @col do %>
          <td><%= render_slot(col, row) %></td>
        <% end %>
      </tr>
    <% end %>
...
1 Like

In your case, maybe try:

<.accordion let={%{parent_id: parent_id}}>
    <.accordion_item show  parent_id={parent_id} show>
      <:header>
        Accordion Item #1
      </:header>
      <:body>
        <strong>This is the first item's accordion body.</strong> It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
      </:body>
    </.accordion_item>
  </.accordion>

1 Like

Thank you Nduatik - i am trying out the solution you have given. Will update if it is working.

@kartheek is this solution working for you?

We would like to merge some additional assigns when calling render_slot, how can it be done?

Thank you @NduatiK - your point about passing data using let provides a solution to the problem.

A small change in the code was needed let={%{parent_id: parent_id}} should be replaced with let={data}

 <.accordion let={data}>
     <.accordion_item show parent_id={data.parent_id}>

There is a small nuance - data passed via render_slot(@inner_html, @data) is available through the variable named in let={<variable_name>} and not through assigns.


@cblavier I did not find a way to modify assigns like i was expecting. Only way to pass data to @ inner_block from component is through argument and access it via let={<var>} . Then you will have to manually set to assigns like parent_id .

2 Likes