Sitelet https://web.archive.org/web/20220709112621/https://github.com/github/view_component/issues/1231
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rendering a collection with dynamically-chosen components #1231

Open
boardfish opened this issue Jan 6, 2022 · 4 comments
Open

Rendering a collection with dynamically-chosen components #1231

boardfish opened this issue Jan 6, 2022 · 4 comments

Comments

@boardfish
Copy link
Collaborator

@boardfish boardfish commented Jan 6, 2022 •

Feature request

I've just finished talking with @coder2000 about this. They were trying to render a collection, rendering different components based on another argument. So their aim was for User::Component to render a collection of User::Actives, for example. It's got me thinking about how collections would work with dynamically chosen components — that seemed to be their original aim as they've mentioned in a discussion. There's been some talk about rendering the same component with different templates in the past, which I've done some work to try and establish patterns for, but this was a nice reminder that it still sort of needs to be thought about for collections.

Let's say you're rendering a list of user profiles, some of which you'd like to show in less detail because they're incomplete, not visible, or otherwise. One way you could do that is to render FullProfileComponents, and render NullProfileComponents for those that aren't present. I think it would follow that you should be able to create a 'factory component' like this:

class ProfileComponent < ApplicationComponent
  with_collection_parameter :profile

  def self.new(profile:)
    (profile.complete? ? FullProfileComponent : NullProfileComponent).new(profile: profile)
  end
end
<%= render ProfileComponent.with_collection(@profiles) # renders `Full` and `NullProfileComponent` on a case-by-case basis %>

The only thing stopping this at present is validate_collection_parameter, which should check .new's parameters as well as #initialize. I wanted to open up discussion before making any changes - what do folks think about this as a pattern?

@joelhawksley
Copy link
Contributor

@joelhawksley joelhawksley commented Jan 27, 2022

@boardfish interesting. For the sake of comparison, can you provide example code for how you would accomplish this using partials?

@boardfish
Copy link
Collaborator Author

@boardfish boardfish commented Jan 27, 2022

You could do something like this:

<%# app/views/profiles/_profile.html.erb %>
<%= render (profile.complete? ? 'full_profile' : 'null_profile'), profile: profile %>
<%# app/views/profiles/index.html.erb %>
<%= render @profiles %>

I guess it's also achievable this way:

<%# app/views/profiles/index.html.erb %>
<% @profiles.each do |profile| %>
  <%= render (profile.complete? ? 'full_profile' : 'null_profile')
<% end %>

I feel like components that entirely delegate off to other components like this based on their input could be quite an intuitive pattern, and may address a lot of the calls for a component being able to render multiple different templates.

@joelhawksley
Copy link
Contributor

@joelhawksley joelhawksley commented Feb 8, 2022

render @profiles

That's the case I'd be most interested in supporting 👍🏻

@boardfish
Copy link
Collaborator Author

@boardfish boardfish commented Feb 8, 2022

Yeah, I think it really clearly marks the benefit of this as a feature. 👍

render @profiles currently makes use of to_partial_path as I understand it, so the implementation is directly linked to partials. I suppose what would be nice is for collection rendering to be able to use render_in somehow... A little bit vague right now, but I might do a bit of digging soon to try and understand how best this could fit into ViewComponent and/or Rails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants