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

Children like support for macros / included templates #1077

Open
michalvankodev opened this issue Jul 15, 2024 · 5 comments
Open

Children like support for macros / included templates #1077

michalvankodev opened this issue Jul 15, 2024 · 5 comments

Comments

@michalvankodev
Copy link

So I did some research and I'd like to open this as a discussion because I haven't been able to find a good solution to this convention.

Problem

Just like in many other templating languages, I'd like to create a wrapper component template that can be re-used with different content inside the template.

This is in some frameworks referred to as <slot/> or children in react.

With Jinja this pattern is possible with the caller functionality with macros: https://jinja.palletsprojects.com/en/3.0.x/templates/#call

Workaround Example

My current solution is to create 2 macros and put the content in between.
This can however cause a few problems when used incorrectly.

  {% call sc::social_card_start("profile", "Beautiful header content goes here") %}
    <span> Here I have total freedom unrelated to the rest of the <code>social_card</code> component </span>
  {% call sc::social_card_end() %}
{% macro social_card_start(svg, heading) %}

<section class="border rounded-md bg-pink-200 m-4 p-4">
	<header class="flex text-center justify-center items-center gap-2 mb-2">
		 <svg aria-hidden="true" class="h-7 w-7 fill-blue-950">
	    <use xlink:href="/svg/icons-sprite.svg#{{svg}}" />
	  </svg>
		<h3 class="text-lg font-medium mb-1">{{heading|safe}}</h3>
	</header>

{% endmacro %}

{% macro social_card_end() %}
	</section>
</section>
{% endmacro %}

Resolution

I've seen that the support for caller was multiple times declined: #996 #930

This brings me to a question: How should I approach creating and using templates that are meant to wrap around different content?

@djc
Copy link
Owner

djc commented Sep 16, 2024

I think the standard approach would be to use template inheritance? (To be clear, you can have multiple levels of inheritance IIRC.)

(Sorry for the slow response.)

@michalvankodev
Copy link
Author

michalvankodev commented Sep 25, 2024

I think the standard approach would be to use template inheritance? (To be clear, you can have multiple levels of inheritance IIRC.)

I have no idea how can this be done with template inheritance.

I am not able to use {% extends %} in a child template. But extending doesn't make sense anyway. I want to display multiple components with the same template.

Maybe it is not clicking to me how can I use this but I'd need to define all component templates in the base.html template so they can be used. Each component must have prefixed block names so they don't overwrite each other when used. Another thing is either I write another template for each usage of the component or I just write a big {% let .... %} bindings prior to importing each time.

This all applies if I understand correctly how this works. Either way, this doesn't help make the code modular. More the other way around.

@djc
Copy link
Owner

djc commented Sep 25, 2024

I guess I don't understand your use case very well. Are you aware, too, that templates implement Display as well, so you can easily nest templates (that is, just pass a value that itself implements Display and render it). Maybe consider a minimal full example of what you're trying to do and why macros/inheritance/includes/nested templates are not sufficient.

@michalvankodev
Copy link
Author

I am aware of that. From my workaround example it should be easy to understand that I am just creating a reusable wrapper component. I want to allow parent template to be the one that sends the content into the child template. I want to do this within the templates themselves.

Another example could be this:

{% macro social_card(svg, heading, content) %}

<section class="border rounded-md bg-pink-200 m-4 p-4">
	<header class="flex text-center justify-center items-center gap-2 mb-2">
		 <svg aria-hidden="true" class="h-7 w-7 fill-blue-950">
	    <use xlink:href="/svg/icons-sprite.svg#{{svg}}" />
	  </svg>
		<h3 class="text-lg font-medium mb-1">{{heading|safe}}</h3>
	</header>
        {{content}}
</section>
{% endmacro %}

{% call sc::social_card(
"profile", 
"Beautiful header content goes here",
"<span> Here I have total freedom unrelated to the rest of the <code>social_card</code> component </span>"
)

@djc
Copy link
Owner

djc commented Sep 25, 2024

I think this is something I would use nested template types for, that seems to map well to "reusable wrapper component"?

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