-
Firstly, please forgive me if I'm taking the liberty of coining a name for an idiom which already exists within the use cases of this library. I've done extensive searching and couldn't find anything similar. What I mean by a "floating slot" is a component slot defined by some component, but not referenced within the component's template. Instead it is rendered by an ERB execution tag ( I did this to achieve rendering a slot within the component's However my question is is this supposed to work, or am I doing something dangerous/unsupported? In the case of the latter, is there a better way to achieve what I need here? Rendering slots inside variable content seems like it would be a somewhat common use case but this feels dirty. Thank you for taking the time to read this. ExamplePrimary component:
|
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
Seems fine to me! I think about slots as just defining another public method on the component class. It could be worth adding a comment to suggest that the As an aside, I don't know if you've seen the capture compatibility patch already? That might alleviate some of your form concerns. |
Beta Was this translation helpful? Give feedback.
-
Hey @rhysb27, interesting question! As @boardfish says, this seems fine to me as well, but it's not really how slots were designed to be used. I feel like what you're doing works sort of by accident 😅 It would be more inline with the spirit of the slots API to refactor a bit. Here are a couple of alternative ideas. Plain 'ol ruby methodsThe idea here is to define a method called
class SyncComponent < ViewComponent::Base
def status_progress_spinner(**kwargs)
SyncStatus::ProgressSpinnerComponent.new(**kwargs)
end
# ... more code here
end
<%= render SyncComponent.new("notes") do |sync| %>
<%= simple_form_for @foo, url: foo_note_path(@foo), html: { "x-ref": sync.form_ref } do |f| %>
<%# Executing the slot in the view instead: %>
<%= render(sync.status_progress_spinner) do %>
<%= f.input :notes %>
<% end %>
<% end %>
<% end %> Using compositionHere, an instance of
class SyncStatus::ProgressSpinnerComponent < ViewComponent::Base
def initialize(sync:, **kwargs)
@sync = sync
end
end
class SyncComponent < ViewComponent::Base
attr_reader :id, :turbo_frame_id, :form_ref
def initialize(id)
@id = id
@turbo_frame_id = "live_update_ack__#{id}"
@form_ref = "live_update_form__#{id}"
end
end
<%= render SyncComponent.new("notes") do |sync| %>
<%= simple_form_for @foo, url: foo_note_path(@foo), html: { "x-ref": sync.form_ref } do |f| %>
<%# Executing the slot in the view instead: %>
<%= render(SyncStatus::ProgressSpinnerComponent.new(sync: sync)) do %>
<%= f.input :notes %>
<% end %>
<% end %>
<% end %> |
Beta Was this translation helpful? Give feedback.
Hey @rhysb27, interesting question! As @boardfish says, this seems fine to me as well, but it's not really how slots were designed to be used. I feel like what you're doing works sort of by accident 😅 It would be more inline with the spirit of the slots API to refactor a bit. Here are a couple of alternative ideas.
Plain 'ol ruby methods
The idea here is to define a method called
#status_progress_spinner
that returns an instance of the component. The return value can berender
ed in the view like any other component. Using a slot instead will wrap the component in an instance ofViewComponent::Slot
, which is fine but unnecessary.app/components/sync_component.rb