I have a modal which I want to turn into a templatetag component. The template needs to ammodate parameters, blocks, and extra content. An example of the template is below. I have something working for the args, and extract content (which is just injected to a {{ content }} tag. But I’m not sure how to do the blocks. Can anyone help?
template
<div id="{{ id|default:'modal-0' }}"
data-modal-placement="{{ placement|default:'center-center' }}"
{% include 'common/components/attrs.html' %}>
<div class="relative h-full w-full p-4 md:h-auto {{ size|default:'max-w-2xl' }}">
<div class="relative rounded-lg bg-white shadow">
{% block modal_header %}
<div class="flex items-start justify-between rounded-t border-b p-4">
<h3 class="text-xl font-semibold text-gray-900">{{ title }}</h3>
{% block modal_close %}
<button type="button" class="ml-auto inline-flex items-center rounded-lg bg-transparent p-1.5 text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900" data-modal-toggle="{{ id|default:'modal-0' }}">
{% heroicon_outline 'x-mark' stroke_width=2 size=20 %}
<span class="sr-only">Close modal</span>
</button>
{% endblock modal_close %}
</div>
{% endblock modal_header %}
{% block modal_body %}
<div class="p-6">
{{ content }}
{% block modal_content %}
<p class="response-message text-base leading-relaxed text-gray-500"></p>
{% endblock modal_content %}
</div>
{% endblock modal_body %}
{% block modal_footer %}
<div class="flex justify-end space-x-2 rounded-b border-t border-gray-200 p-6">
{% block modal_buttons %}
{% endblock modal_buttons %}
</div>
{% endblock modal_footer %}
</div>
</div>
</div>
class RenderComponentNode(template.Node):
def __init__(self, template_name, context_args, context_kwargs, nodelist):
self.template_name = template_name
self.context_args = context_args or {}
self.context_kwargs = context_kwargs or {}
self.nodelist = nodelist
def render(self, context):
resolved_context_args = {
key: (value.resolve(context) if not isinstance(value, str) else value)
for key, value in self.context_args.items() if value
}
resolved_context_kwargs = {
key: (value.resolve(context) if not isinstance(value, str) else value)
for key, value in self.context_kwargs.items() if value
}
content = self.nodelist.render(context)
ctx = {'content': content, 'attrs': resolved_context_kwargs}
ctx.update(resolved_context_args)
return render_to_string(self.template_name, ctx)
@register.tag
def render_component(parser, token, template_name, context_args):
try:
tag_name, *args = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError(f"{tag_name} tag requires at least one argument.")
context_kwargs = {}
for arg in args:
try:
name, value = arg.split('=')
if name in context_args.keys():
context_args[name] = parser.compile_filter(value)
else:
context_kwargs[name] = parser.compile_filter(value)
except ValueError:
context_args[arg] = None
nodelist = parser.parse(('end_' + tag_name,))
parser.delete_first_token()
return RenderComponentNode(template_name, context_args, context_kwargs, nodelist)