Forwarding slots to subcomponents #879
-
Hi! Firstly, thank you for this wonderful gem :) Now, I'm trying to pass slots from a component to another. I've found a way to do it but that does not seem very reliable. Is there a more "official" system? I want to be able to do that: render ListComponent.new do |list|
list.category("vegetables") do |category|
category.item("tomato")
category.item("carrot")
end
list.category("fruits") do |category|
category.item("apple")
end
end
# or when you don't want categories, you can call items directly
# and a "All" category is implicitly created
render ListComponent.new do |list|
list.item("tomato")
list.item("apple")
end
# so it should render exactly the same as
render ListComponent.new do |list|
list.category("All") do |category|
category.item("tomato")
category.item("apple")
end
end The current implementation works but seems flaky: class ListComponent < ViewComponent::Base
renders_many :categories, CategoryComponent
renders_many :items, ItemComponent
def call
if categories.empty?
render CategoryComponent.new("All") do |category| # <- the implicit "All" category
items.each { |item| item.instance_variable_set("@parent", category) }
category.instance_variable_set("@_set_slots", { items: items }) # <- passing items to it
end
else
categories
end
end
end
class CategoryComponent < ViewComponent::Base
renders_many :items, ItemComponent
def initialize(title)
# ...
end
def call
# ...
end
end Any suggestion? Did I miss something? Thank you :) |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
I would try to avoid
|
Beta Was this translation helpful? Give feedback.
-
Ok so new working and certainly less flaky implementation, thanks to @BlakeWilliams class ListComponent < ViewComponent::Base
renders_many :categories, CategoryComponent
renders_many :items, ItemComponent
def call
if categories.empty?
# the implicit "All" category, f_items for "forwarded_items")
render CategoryComponent.new("All", f_items: items)
else
categories
end
end
end
class CategoryComponent < ViewComponent::Base
renders_many :items, ItemComponent
def initialize(title, f_items: [])
@f_items = f_items
end
def call
@f_items.concat(items).each { ... }
end
end |
Beta Was this translation helpful? Give feedback.
I would try to avoid
instance_variable_set
since that's utilizing a private API and you're overriding any other slots set in that component.items
is an array of slots, maybe you could pass it to the CategoryComponent viadef initialize(title, items:)
?