ViewComponent / view_component

A framework for building reusable, testable & encapsulated view components in Ruby on Rails.
https://viewcomponent.org
MIT License
3.32k stars 440 forks source link

Child Component Content Blocks Not Rendering in Parent Component #2157

Open Eth3rnit3 opened 2 weeks ago

Eth3rnit3 commented 2 weeks ago

When rendering a parent component with multiple child components, the content blocks provided to each child are not displayed as expected. Instead of rendering the <p> content within each child component's container <div>, the child components appear empty in the HTML output. This issue suggests that the blocks passed to each child are not being processed or rendered correctly within the parent-child component structure.

Steps to reproduce

  1. Set up the component structure:

    • Create an AccordionComponent in app/components/accordion_component.rb to render multiple Accordion::ItemComponent components.
    # app/components/accordion_component.rb
    class AccordionComponent < ViewComponent::Base
     renders_many :items, Accordion::ItemComponent
    end
  2. Define the template for the AccordionComponent:

    • In app/components/accordion_component.html.erb, iterate over each item to render its content.
    <!-- app/components/accordion_component.html.erb -->
    <div class="accordion">
     <% items.each do |item| %>
       <%= render item %>
     <% end %>
    </div>
  3. Create the Accordion::ItemComponent:

    • Define the Accordion::ItemComponent with an initializer that accepts a title parameter.
    # app/components/accordion/item_component.rb
    class Accordion::ItemComponent < ViewComponent::Base
     def initialize(title:)
       @title = title
     end
    end
  4. Define the template for Accordion::ItemComponent:

    • In app/components/accordion/item_component.html.erb, render the title and the content passed to the item component.
    <!-- app/components/accordion/item_component.html.erb -->
    <h2>Item <%= @title %></h2>
    <div class="accordion-item">
     <%= content %>
    </div>
  5. Use the component in a view:

    • In app/views/application/home.html.erb, render the AccordionComponent with three items, each containing specific content in a block.
    <!-- app/views/application/home.html.erb -->
    <%= render(AccordionComponent.new) do |accordion| %>
     <% accordion.with_item title: :to_classify do %>
       <p>Items that need to be classified.</p>
     <% end %>
    
     <% accordion.with_item title: :classified do %>
       <p>Items that have been classified.</p>
     <% end %>
    
     <% accordion.with_item title: :rejected do %>
       <p>Items that have been rejected.</p>
     <% end %>
    <% end %>
  6. Render the page and check the HTML output:

    • Run the server and navigate to the view rendering home.html.erb.
    • Observe the generated HTML output in the browser or inspect it through the page source.

Expected behavior

The content within each Accordion::ItemComponent should be rendered inside the accordion-item <div>. Each item should display the title and the specified content:

<div class="accordion">
  <h2>Item to_classify</h2>
  <div class="accordion-item">
    <p>Items that need to be classified.</p>
  </div>

  <h2>Item classified</h2>
  <div class="accordion-item">
    <p>Items that have been classified.</p>
  </div>

  <h2>Item rejected</h2>
  <div class="accordion-item">
    <p>Items that have been rejected.</p>
  </div>
</div>

Actual behavior

The content inside each Accordion::ItemComponent is missing. The rendered HTML output does not contain the expected <p> content within each accordion-item <div>, resulting in an empty structure:

<body>
    <main class="container mx-auto mt-28 px-5 flex">
      <!-- BEGIN app/views/application/home.html.erb --><!-- BEGIN app/components/accordion_component.html.erb --><div class"accordion"="">
    <!-- BEGIN app/components/accordion/item_component.html.erb --><h2>Item to_classify </h2>
<div class"accordion-item"="">

</div><!-- END app/components/accordion/item_component.html.erb -->
    <!-- BEGIN app/components/accordion/item_component.html.erb --><h2>Item classified </h2>
<div class"accordion-item"="">

</div><!-- END app/components/accordion/item_component.html.erb -->
    <!-- BEGIN app/components/accordion/item_component.html.erb --><h2>Item rejected </h2>
<div class"accordion-item"="">

</div><!-- END app/components/accordion/item_component.html.erb -->
</div><!-- END app/components/accordion_component.html.erb --><!-- END app/views/application/home.html.erb -->
    </main>
</body>

This indicates that the content passed to each with_item block is not being rendered inside the component.

System configuration

Rails version: 7.2.2 Ruby version: 3.2.2 Gem version: view_component version 3.20

enzofab91 commented 2 days ago

I'm having same issue but with Ruby 3.3.1. Did you find a solution?

reeganviljoen commented 2 days ago

If anyone is willing to add a failing test it would help towards fixing this issue otherwise I will do it when I have some time