-
Notifications
You must be signed in to change notification settings - Fork 444
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 components outside of view context #201
Comments
Not sure if I understand correctly, and maybe this is too hacky, but could you set up a fake view context in much the same way that |
@dylnclrk @joelhawksley Thank you both! I did something similar too, the following code worked fine for a very simple component :
but it felt too hacky and probably it's not a good idea to call |
@dennyf What if we had changed def render_in(view_context, *args, &block) to: def render_in(view_context = ActionView::Base.new, *args, &block) I'm not sure if that would work in all cases, but I think we'd be fine to use that kind of fallback. |
@joelhawksley Thanks, that's good to hear! Actually I just noticed that Rails is throwing a warning when initializing
so I guess it won't be as simple as that, I think it will be an overkill to initialize it with all the required parameters... I'll see if I can get any other ideas. |
@dennyf It might be possible to provide all of those things, FWIW. Let me know if you want to have a look at this together: [email protected] |
@joelhawksley Sorry for the late reply - my schedule is very ovestretched these days - the best I can do is spend a few minutes here and there when I get any free time. So can we continue the discussion here in this issue? In this way I can be more flexible with my time. As for providing all the options - I noticed that at this point component = MyComponent.new(title: param)
# not sure if that's the best way to create a lookup context
lookup_context = ActionView::LookupContext.new(ActionController::Base.view_paths)
view = ActionView::Base.new(lookup_context, {})
component.render_in(view) so technically it should be okay to go without passing a controller instance for now... or do you think it's better to pass a controller as well in case things change in the future? |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
This doesn't work in
|
@ramontayag Use of helpers means that your component is coupled to the view context. You could consider including the helpers directly on the component class so that it's decoupled from the view context. Alternatively, Joel's solution might work for you. |
I see. Is it generally recommended to override that method? In the past, I've done something like this: def helpers
return @helpers if @helpers
helpers = Object.new
helpers.extend SomeHelper
helpers.extend AnotherHelper
@helpers = helpers
end |
Hi @ramontayag! I think what @boardfish meant was: class ExampleComponent < ViewComponent::Base
include SomeHelper
include AnotherHelper
# ...
end This makes the methods defined in You don't need to override the |
Ah yes, definitely another way. Thank you @Spone |
@joelhawksley's original suggestion about setting a default has become relevant again as it'll be useful for the default use case in #1106, i.e. rendering components to broadcast via Turbo Streams in Active Record callbacks. What do folks think of using |
FYI, in Rails 6.1 simply calling This works for me: ActionView::Base.new(ActionView::LookupContext.new([]), {}, nil) |
👋 catching back up here, my official recommendation is: ApplicationController.new.view_context.render(MyComponent.new) I'm going to go ahead and close this issue. If anyone thinks we should add this recommendation to the docs, please reply with a comment ❤ |
Yes, maybe we could add this over there? https://viewcomponent.org/guide/getting-started.html#rendering-from-controllers |
I think I'm misunderstanding this recommendation, because I keep running into errors when I try to use it. Can someone help me understand this? I just tried updating my code in an after_create_commit -> {
broadcast_prepend_to(
"#{user_id}-activities",
target: "activities",
html: ApplicationController.render(ActivityComponent.new(activity: self), layout: false)
)
} to what I understand is the new suggested syntax: after_create_commit -> {
broadcast_prepend_to(
"#{user_id}-activities",
target: "activities",
html: ApplicationComponent.new.view_context.render(ActivityComponent.new(activity: self), layout: false)
)
} This caused the error after_create_commit -> {
broadcast_prepend_to(
"#{user_id}-activities",
target: "activities",
html: ::ApplicationComponent.new.view_context.render(ActivityComponent.new(activity: self), layout: false)
)
} but this resulted in a similar error I noticed I didn't have my own Rails 7.1.4 |
@JamesChevalier my apologies, that was a typo. It should be |
Thanks! 🫣 I found myself running into another issue, but it was definitely outside of the scope of ViewComponent. I'll explain below, to either help other people running into the same problem or to be corrected. ApplicationController.new.view_context.render(ActivityComponent.new(activity: activity), layout: false) Resulted in this error:
I decided to try it with a partial, to check if it was ViewComponent-specific: ApplicationController.new.view_context.render('activities/form', activity: Activity.first) This resulted in the same error, with a little more context (it referred to url_for.rb#L39):
This pointed out that I had no ApplicationController.renderer.render template: "posts/show", assigns: { post: Post.first } This translated well into ViewComponent: ApplicationController.renderer.render(ActivityComponent.new(activity: activity), layout: false) |
I had the issue that images uploaded with ActiveStorage weren't rendering properly when I broadcast them rendered with |
How does this hook up with the support for multiple formats? I've tried using render as normally would, but that doesn't seem to work as it only renders html when used outside the controller. Use case is using view components to handle Mailer views
Tried also hardcoding the value of format in my component
Any pointers are welcome 😊 |
I'm trying to find if there is a way to render a component outside of the view context. I'm working on a feature to register a custom tag in my markdown processor - so basically, I want to replace the custom tag/shortcode with the markup generated by a component.
So, I'm wondering if there is a way to call the component to generate the markup from another class, outside the view context?
Thanks!
The text was updated successfully, but these errors were encountered: