-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Using variables as snippet name in render tags #1269
Comments
The reasoning was provided in the pull request that introduced the render tag (#1122)
If you are just rendering a different partial based on whether the user is logged in or out, then you could just use conditional control flow to render the appropriate nested partial. If you want your partial to be more generic so that it isn't coupled to the nested content, then you could capture the rendering of the nested content and pass the rendered content into the generic partial. For example, that would allow you to pass in different attributes to different nested partials, as you have done with |
What we will do if things go like this? I need to show flags according to user input, there are literally hundreds of them. Writing hundreds of if-else statements will be somewhat cumbersome. |
What puzzles me about this answer is that the official documentation seems to contradict it, but I can't get it to work. |
Do you mean you have literally hundreds of snippets that you might need to dynamically include? If so, that seems cumbersome even with the include tag.
That isn't referring to assigns. Look at the global objects in the documentation that it links to. Are any of those not accessible from all files? |
Found this workaround. By appending a string (even empty) it transforms the variable into a string.
Found on this thread. |
That is clearly relying on a bug. Intentionally relying on a bug is fragile to changes we make to liquid or Shopify's extensions to liquid, since it puts you code at risk from breaking from a bug fix. |
Looks like that was another bug in Shopify that has already been fixed. It should now render to the error: |
Any updated on this? The feature would be awesome! |
+1, please. |
|
+1 |
I found a solution for this one. Just extend the Render class and create a CustomRender class. The code should be something like this: class CustomRender < Liquid::Render
SYNTAX = /(?:#{QuotedFragment}|#{VariableSegment})(\s+(with|for)\s+(#{QuotedFragment}+))?(\s+(?:as)\s+(#{VariableSegment}+))?/o
def initialize(tag_name, markup, options)
super
# Update the syntax to support variables or string fragments
match = markup.match(SYNTAX)
template_name = match[0]
@variable_name_expr = match[3] ? parse_expression(match[3]) : nil
@template_name_expr = parse_expression(template_name)
@alias_name = match[5]
@attributes = {}
markup.scan(TagAttributes) do |key, value|
@attributes[key] = parse_expression(value)
end
end
def render_tag(context, output)
# Allow variable-based template names
template_name = context.evaluate(@template_name_expr)
raise ::ArgumentError unless template_name.is_a?(String)
# Load the partial (same as the original code)
partial = PartialCache.load(
template_name,
context: context,
parse_context: parse_context,
)
context_variable_name = @alias_name || template_name.split('/').last
render_partial_func = ->(var, forloop) {
inner_context = context.new_isolated_subcontext
inner_context.template_name = partial.name
inner_context.partial = true
inner_context['forloop'] = forloop if forloop
@attributes.each do |key, value|
inner_context[key] = context.evaluate(value)
end
inner_context[context_variable_name] = var unless var.nil?
partial.render_to_output_buffer(inner_context, output)
forloop&.send(:increment!)
}
variable = @variable_name_expr ? context.evaluate(@variable_name_expr) : nil
# Support for loops (same as the original code)
if @is_for_loop && variable.respond_to?(:each) && variable.respond_to?(:count)
forloop = Liquid::ForloopDrop.new(template_name, variable.count, nil)
variable.each { |var| render_partial_func.call(var, forloop) }
else
render_partial_func.call(variable, nil)
end
output
end
end Then override the render tag or name it anything you want (In my case, I override my render tag): Liquid::Template.register_tag('render', CustomRender) |
You can use this method instead Snippet <div>
{{ content }}
</div> In a section <section>
{% capture my_content %}
{% render 'icon' %}
{% endcapture %}
{% render 'button', content: my_content %}
</section> Render <section>
<div>
<svg>
...
</svg>
</div>
</section> |
Hi!
It seems pretty unreasonable (as an outsider) that I can't do this:
I can't understand why
render
should care if the string it uses is inline or from a variable, so long as its a string.This feature would be useful for rendering partials based on things that need to be dynamic (For example rendering a different partial if a user was logged in or out) or when you want to make components more generic.
For example, say I have a bunch of
svg
icons as.liquid
files. I want to render them, wrapped with some markup. Rather than edit each icon with repetitive wrapping HTML, I want to create an adapter component and pass in the icon name so I could write:And then inside
snippets/icon.liquid
Am I being dense? This feels like a step back from
include
tags.Cheers
Matt
The text was updated successfully, but these errors were encountered: