A for loop in my jinja template is like this
{% for m in grp %}
abc {{ m.length }}
pqr
xyz
{% if m.flag is defined and m.flag == "f" %}
yes f {% endif %}
{% for r in uv %}
abcdef
{% endfor %}
{% endfor %}
Now the problem is in some members of grp don't have the flag variable. Wherever flag is present, the option true line is getting added properly. But when if condition is not satisfied, it just adds one blank line. These 4 or 5 lines are supposed to be without extra blank lines otherwise the generated config file gets marked as invalid.
Can anyone please help me with this?
Put {% endif %} to the next line
{% if m.flag is defined and m.flag == "f" %}
yes f
{% endif %}
Whitespace Control might be useful too.
If you add a minus sign (-) to the start or end of a block (e.g. a For tag), a comment, or a variable expression, the whitespaces before or after that block will be removed.
{% if m.flag is defined and m.flag == "f" %} yes f
{% endif -%}
Related
I have very few hours of use with Twig so I probably missed an important tip; please forgive me if this is a trivial question.
I'm using Twig with PHP for the generation of markdown files.
My twig file contains one or more {% for %}...{% endfor %} block and inside a for-loop, a few {% if %}...{% endif %} and ... I can't make any indentation in my Twig otherwise the spaces are also present in my output.
A very stupid example: https://twigfiddle.com/fb6nzq (use the Show raw result to make sure to see the spaces before the word true).
If I don't indent my {% if %}...{% endif %}, I got the correct result (https://twigfiddle.com/fb6nzq/2) but I don't have anymore indentation of blocks in my template.
In my real world twig file, I can have multiple {% endif %} like below and it becomes unreadable.
{% for (variable) %}
{% if (condition) %}
{% if (condition) %}
{% if (condition) %}
{% endif %}
{% endif %}
{% endif %}
{% endfor%}
So ... do you know if there is a wonderful trick to keep an indentation in your code but without having an impact on the output?
Desired twig template:
{% for (variable) %}
{% if (condition) %}
{% if (condition) %}
{% if (condition) %}
{% endif %}
{% endif %}
{% endif %}
{% endfor%}
You can use a dash - on any opening or closing twig expression where:
a dash on the closing expression would do a trim on the left.
{% if true -%}
a dash on the opening expression would do a trim on the right
{%- if true %}
a dash on the both the opening and closing expression would do a trim on the both sides
{%- if true -%}
Mind that: this is acting as a PHP trim, so that means that it will also trim your line feeds!
Here is an example:
{% for i in 1..5 %}
{% if true %}
{% if true %}
{%- if true %}
foo
{%- endif %}
{%- endif %}
{% endif %}
{% endfor %}
That renders:
foo
foo
foo
foo
foo
This is testable here: https://twigfiddle.com/1awhzk
Also note: that there is a spaceless tag to achieve those kind of things.
My template like as blow
{% if hostvars[inventory_hostname].local_zk_server_id is defined %}
zookeeperServers={% for host in {{ groups[{{ target_hosts }}] %}}
"{{ hostvars[host].inventory_hostname }}:2181,"
{% endfor %}
{% endif %}
output ishost1:2181,host2:2181,host3:2181,
How to trim last comma
There are several possible gotchas in your above template regarding variables access. Moreover, rather than trimming the last character in your string, the best solution is probably not to write it. Here is a better solution IMO in my below example fixing all the problems I'm referring to:
{% set zookeeperServers=[] %}
{% if hostvars[inventory_hostname].local_zk_server_id is defined %}
{% for host in groups[target_hosts] %}
{% zookeeperServers.append(hostvars[host].inventory_hostname + ":2181") %}
{% endfor %}
zookeeperServers="{{ zookeeperServers | join(',') }}"
{% endif %}
I got this piece of YAML and i want jinja2 to assign and create item.menu, if it is not previously defined.
data:
- name: bar
menu: blah
- name: foo
This is my code, the error-output ist "template error while templating string: expected token 'end of statement block'"
{% for item in data %}
{% if item.menu is not defined %}
{% set item.menu=item.name %}
{% endif %}
{% endfor %}
Any Help about what I did wrong would be much apretiated :)
Greetings, Hendrik
You're question is not clear but here is my answer. I'll make everything explicit :
{% for item in data %}
{% if item.menu is not defined %}
{{ item.nameĀ }}
{% else %}
{{ item.menu }}
{% endif %}
{% endfor %}
We're trying to come up with a way to use ansible facts within jinja2 For Loops.
For example, I want to get all servers that belong to my memcached group as well as a group based on release (something like tag_release_dev or tag_release_prod). When I try to use {{ tt_release }} within the For Loop it evaluates {{ tt_release }} rather than the value of the variable. Is there a way to use a variable within the loop definition?
{% for host in groups["tag_function_mem"] | intersect(groups["tag_release_{{ tt_release }}"]) %}
{{ host }}:11211
{%- if not loop.last %},{% endif %}
{%- if loop.last %}"{% endif %}
{% endfor %}
{% endif %}
it evaluates {{ tt_release }} rather than the value of the variable.
This is because you already are inside a expression. You can not nest expressions - and you don't need to.
What you want is to concatenate the string "tag_release_" and the variable tt_release. In Jinja2 concatenation is done with a +.
{% for host in groups["tag_function_mem"] | intersect(groups["tag_release_" + tt_release]) %}
Jinja2 in Ansible templates allows this type of expression in templates:
{% if foobar is defined %} foo_bar = {{foobar}} {% endif %}
{% if barfoo is defined %} bar_foo = {{barfoo}} {% endif %}
etc.
Is there any shorter version to say 'do not print this line if its variable is not defined?
Something like foo_bar = {{foobar|skip_this_line_if_undefined}}?
You can use the default(omit) filter. For details have a look at the documentation.
You could use a macro.
{% macro line(key, value) -%}
{% if not value|none %}{{ key }} = {{ value }}{% endif %}
{%- endmacro %}
Then just call the macro for every key/value pair.
{{ line('foo_bar', foobar) }}
{{ line('bar_foo', barfoo) }}
Could be problematic in edge cases though. If foobar or barfoo are not defined it probably will raise an error. In the macro, value in any case would be defined, so the condition is defined doesn't make sense any more. But if null/none actually is a valid value for any of the variables, you hit the wall...
A bit longer but probably water proof:
{% macro line(key, value) -%}
{% if value != omit %}{{ key }} = {{ value }}{% endif %}
{%- endmacro %}
{{ line('foo_bar', foobar|default(omit)) }}
{{ line('bar_foo', barfoo|default(omit)) }}