Reputation: 443
I'm using flask with jinja.
I know that you can define a base page template with multiple placeholder blocks:
<html>
<head>
[ standard meta tags, etc go here ]
{% block css %}{% endblock %}
</head>
<body>
[ standard page header goes here ]
{% block content %}{% endblock %}
[ standard page footer goes here ]
{% block javascript %}{% endblock %}
</body>
</html>
And I know that you can define a macro with a single placeholder:
{% macro dialog() %}
<div class="dialog">
[ standard dialog header ]
{{ caller() }}
</div>
{% endmacro %}
{% call dialog() %}
<div class="log-in">
Log in or sign up! (etc.)
</div>
{% endcall %}
But is it possible to define a macro with multiple placeholder blocks?
Upvotes: 6
Views: 2131
Reputation: 159
Thanks to muffel, I modified his answer and figured out this
{# macro defined file #}
{% macro card_block() %}
<div class="card block-use">
<div class="card-header">
{{ caller('header') }}
</div>
<div class="card-body">
{{ caller('body') }}
</div>
</div>
{% endmacro %}
Now we can use it template
{# template page #}
{% from 'modules/components/card-block.html' import card_block %}
{% call(content) card_block() %}
{% if content == 'header' %}
<div>Header</div>
{% endif %}
{% if content == 'body' %}
<div>Body</div>
{% endif %}
{% endcall %}
Output like
<div class="card block-use">
<div class="card-header">
<div>Header</div>
</div>
<div class="card-body">
<div>Body</div>
</div>
</div>
Upvotes: 0
Reputation: 9622
@muffle 's answer is great. However if you don't want your callers to be too complicated since you have provided a standard header by default, you can pass another macro for the header part as its argument.
import jinja2
environment = jinja2.Environment()
template = environment.from_string('''
{% macro dialog(dialog_header) %}
{% if dialog_header %}
{{ dialog_header() }}
{% else %}
Default Header
{% endif %}
{{ caller() }}
{% endmacro %}
---- A
{% call dialog() %}
Dialog body A.
{% endcall %}
---- END-OF-A
---- B
{% macro dialog_header_b() %}
Header B
{% endmacro %}
{% call dialog(dialog_header_b) %}
Dialog body B.
{% endcall %}
---- END-OF-B
''')
print(template.render())
Output (with blank lines trimmed)
---- A
Default Header
Dialog body A.
---- END-OF-A
---- B
Header B
Dialog body B.
---- END-OF-B
(Works with Jinja2==3.0.3
)
Upvotes: 0
Reputation: 7370
No, you can't. While you can pass several parameters to the macro, only one caller
can exist. You can nevertheless pass a parameter back from your macro to the calling context and simulate your desired behavior like this:
{% macro twoblocks()%}
<div class="content-a">
{{ caller(True) }}
</div>
<div class="content-b">
{{ caller(False) }}
</div>
{% endmacro %}
{% call(isA) twoblocks() %}
{% if isA %}
A content
{% else %}
B content
{% endif %}
{% endcall %}
Upvotes: 5