How to escape Twig delimiters in a Twig template? - twig

Twig uses the {{ }}, {% %}, {# #} delimiters.
But how can I display {{ }} in a Twig template?
I'm not talking about HTML escaping.
I ask the question as I want to include a mustache template in my Twig template so that I will fill with data coming from an AJAX call.

The easiest way is to output the variable delimiter ({{) by using a variable expression:
{{ '{{' }}
Alternatives (used when you have to escape too much) are raw (verbatim since 1.12) blocks:
{% raw %}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endraw %}
Actually, it's quite well documented.

The Twig documentation gives two suggestions. The first is simply to output a string:
{{ '{{' }}
Otherwise, if you want to output a long section (it sounds like you do) you can use the raw tag:
{% raw %}
your mustache content here
{% endraw %}

{% block body %}
<table class="table table-striped">
{% for temp in data %}
<tr>
<td>{{temp.fname}}</td>
<td>{{temp.lname}}</td>
</tr>
{% endfor %}
</table>
{% endblock %}

Related

How to check type of variable in Django template

Below is my sample code. I need to know the type of weather variable which may be List, Dictionary, or Tuple. Is there any easy way like we use type() in python?
{% extends 'base.html' %}
{% block title%}
Home
{% endblock %}
{% block content %}
<h3 class="text-center text-success">Weather Forecast!!</h3><hr>
{{weather}}
<hr>
{% for w in weather%}
{{w}}<br/>
{% endfor%}
{% endblock %}
when sending variables to templates use
specific description like {{weather.sun}} or {{weather.cloudy}}

How to reduce duplication in Twig template

I have an if/else condition in a twig template which switches the out tag of a block of code, however the inner block is the same. Is there a way to reduce the duplication without creating a separate file?
This is what I have at the moment:
{% if condition %}
<a href="">
{{ content }}
</a>
{% else %}
<span>
{{ content }}
</span>
{% endif %}
I was hoping to do something such as:
{% if condition %}
<a href="">
{% include mycontent %}
</a>
{% else %}
<span>
{% include mycontent %}
</span>
{% endif %}
{% mycontent %}
{{ content }}
{% endmycontent %}
Is such a thing possible?
If you don't want to use extra files you could use macro's :
{% import _self as macro %}
{% macro foo(content) %}
{{ content }}
{% endmacro %}
{% for condition in [0, 1, 0, 1, ] %}
{% if condition %}
{{ macro.foo('Bar') }}
{% else %}
<span>{{ macro.foo('Bar') }}</span>
{% endif %}
{% endfor %}
fiddle
What you want to do has to be done using the normal syntax. an extra file. and include this file.
But if u want to do this without extra file. use the {% set variablecontent = "put content here" %} and then in your "{% mycontent %}" part u put {{ variablecontent }}
hope this helps

Pass include path from variable with Twig?

I need to include child-1.twig and child-2.twig in component.twig, and include component.twig in page.twig.
In my page.twig:
{% set items = [
'{% include "child-1.twig" %}',
'{% include "child-2.twig" %}'
] %}
{% include "component.twig" with items %}
In component.twig:
<div class="component">
{% for item in items %}
{{ item }}
{% endfor %}
</div>
The complexity comes from the fact that I cant modify component.twig, only page.twig. My code above would work if {% include "child-1.twig" %} and {% include "child-2.twig" %} were rendered but instead they are printed onto the page as a string of text.
Can I do something similar to my approach but make the child include actually run?
Can I suggest you add an empty block in that file (component.twig)
{% block includes %}{% endblock %}
Then you will be able to do this:
{% embed "component.twig" with items %}
{% block includes %}
{% include "child-1.twig" %}
{% include "child-2.twig" %}
{% endblock %}
{% endembed %}

Twig variable variable

There are some Twig arrays:
feeds, where a feed gets category_name;
events, news, announces with posts.
Therefore, I can get posts for a category that way:
{% for feed in feeds %}
{% if feed.category_name == "events" %}
{% for post in events %}
{{post.title}}
{% endfor %}
{% endif %}
{% endfor %}
Can I get the same output (as above one loop returns) with category_name string set as array name?
Here feed.category_name returns events:
{% for feed in feeds %}
{% for post in feed.category_name %} {# feed.category_name == "events" #}
{{post.title}}
{% endfor %}
{% endfor %}
I think what the question author means is – access the array using a name derived from another variable. So that extra conditions are not necessary (and most answers here do propose extra conditions).
Based on my several-minute-research, Volt alone won't let you do it. However, since you can embed PHP code in Volt templates and twig files are compiled to PHP later on anyway, you could do something like:
{% for feed in feeds %}
<?php foreach (${$feed.category_name} as $post) { ?>
{{post.title}}
<?php } ?>
{% endif %}
{% endfor %}
I have already tested this – it does work. You may want to add an extra check if the array exists, to avoid warnings:
{% for feed in feeds %}
<?php
if (!empty(${$feed.category_name})) {
foreach (${$feed.category_name} as $post) {
?>
{{post.title}}
<?php } } ?>
{% endif %}
{% endfor %}
If you don't like the idea of embedding PHP in your template – don't forget that your template is going to be compiled as PHP anyway!
The global variable _context holds all variables in the current context, so you can do this:
{% for feed in feeds %}
{% for post in _context[feed.category_name]|default(null) %}
{{ post.title }}
{% endfor %}
{% endfor %}
The |default(null) is required to prevent Twig from throwing an exception if the variable is not found.
See TwigFiddle
You want the conditional to be "added" to the loop? I think you mean this in Twig Documentation:
<ul>
{% for user in users if user.active %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
Edit
Your main issue was with the "variable variable". You can solve this with the attribute() function and combining the different feeds into one assoc array (categories?).
So perhaps something like (untested):
{% for feed in feeds %}
{% for post in attribute(categories, feed.category_name) %}
{{post.title}}
{% endfor %}
{% endfor %}
Based on your comment :
{% set new_array = news|merge(events) %}
{% for feed in feeds if attribute(feed.category_name, ['events', 'news']) %}
{% for post in new_array %}
{{post.title}}
{% endfor %}
{% endif %}
{% endfor %}

Dynamic block name in TWIG

I need to add multiple blocks in my template, every with different name.
{% for item from items %}
{% block item.name %}sometext{% endblock %}
{% endfor %}
But I get error. How can I do this ?
In
Dynamic block names are not possible with Twig. There has been a discussion about it over at GitHub.
You can load blocks dynamically using the block function.
{% for item in items %}
{{ block( item.name )|raw }}
{% endfor %}
Twig documentation for the block function
If I understood the question correctly, you can do this (use parent context):
parent.html.twig
{% for item from items %}
{% set currentLoopItemName = item.name %}
{% block item_loop %}sometext{% endblock %}
{% endfor %}
override.html.twig
{% extends "base.html" %}
{% block item_loop %}
{% if item.name == 'custom' %}
// do something
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}
I was attempting to do the same thing and found a solution using the template_from_string function.
_items.html.twig
{% for item in items %}
{{ '{% block ' ~ item.name ~ ' %}'}}
sometext
{{ '{% endblock %}' }}
{% endfor %}
enter code here
page.html.twig
{% embed template_from_string(include('_items.html.twig')) %}
{% block someItemName %} someDifferentText {% endblock %}
{% endembed %}
What's happening is the block tags are initially being created as text. Then we use the include function to get the rendered content of _items, as a string. Finally, we convert that string to a working template (which we can embed or extend).
This works because the template_from_string function will create and compile a template at runtime, where as normally twig is compiled before hand and unchanged at runtime.

Resources