`include` statement in `for` loop does not work - nunjucks

// item.html
test
// main.html
{% for i in range(1, 4) %}
abc
{% include "item.html" %}
def
{% endfor %}
{% include "item.html" %}
The output is:
abcabcabctest (three times abc and one time test). It means that for some reason include statement in loop does not work and also anything after the statement, but still inside loop, is not rendered either. However include outside of loop does work. This is almost same as example from docs so I have no idea what might be wrong with this code.
Using nunjucks v3.1.2.

I tested it and it looks like everything is fine.
// app.js
var nunjucks = require("nunjucks");
var env = nunjucks.configure();
var res = env.render("template.html");
console.log(res);
// template.html
{% for i in range(1, 3) %}
{% include "partial"+ i + ".html" %}
{% endfor %}
{% include "partial1.html" %}
// partial1.html
AAA
// partail2.html
BBB

I had the same issue, and I solved it by changing the web loader to synchronous:
this._nunjucksEnvironment = new nunjucks.Environment(
new nunjucks.WebLoader(this.file(""), { async: false }),
{
trimBlocks: true,
lstripBlocks: true
}
);

Related

Remove outside double quotes from list of jinja strings

I'm formatting & appending strings to a list but the ref() function (used in dbt) isn't a string so I need to remove the outside quotes while retaining the inner single quotes.
I've attempted to chain strip() and replace() but neither are solving the problem.
Current code:
{% for result in results_list %}
{% set result = "ref('{}')".format(result) %}
{{ ref_format_results.append(result) }}
{% endfor %}
{% do log(ref_format_results, info=true) %}
Current output:
["ref('model_a')","ref('model_b')","ref('model_c')"]
Desired output:
[ref('model_a'),ref('model_b'),ref('model_c')]
You're creating a string, which needs to be delimited somehow, and will always show outer quotes when printed/logged.
If you're templating those values into another file or string, then you'll already have what you want.
{% for r in ref_format_results %}
select * from {{ "{{" ~ r ~ "}}" }};
{% endfor %}
will produce:
select * from {{ ref('model_a') }};
select * from {{ ref('model_b') }};
select * from {{ ref('model_c') }};
But more importantly, why set result to a string in the first place? Are you trying to delay the execution of the ref() macro? If not, this will work just fine, to give you a list of evaluated refs (which are Relations):
{% for result in results_list %}
{% set result = ref(result) %}
{{ ref_format_results.append(result) }}
{% endfor %}
{% do log(ref_format_results, info=true) %}
Outputs:
['"my_db"."my_schema"."model_a"', '"my_db"."my_schema"."model_b"', '"my_db"."my_schema"."model_c"']

User "elif" in "for" loop with nunjucks

Basically I try to combine multiple conditions in a for loop. For two conditions its working fine
{% for blockName in (userblocks if sitename == "user" else xpertBlocks) %}
but is there also a way, to realize three or more conditions in a for loop, like so:
{% for blockName in (userBlocks if sitename == "user" elif sitename == "xpert" xpertBlocks else "provider") %}
I couldn't find anything in the nunjucks documentation.
{% set chooser = {user: userBlocks, xpert: xpertBlocks, ...} %}
{% set blocks = chooser[sitename] or providerBlocks %}
{% for blockName in blocks %}
...
{% endfor %}

HuBL: Using for loop variable outside for loop

I have created a template partial file where I'm defining all variables in that file. I then want to reference a variable in custom modules. However, the for loop loop closes in the partial file, so when I reference it in the HTML of a custom module, it'll be out of scope.
Is there any way to use for loop variables outside the loop?
Demo:
Here is my template partial file:
<!--
templateType: "global_partial"
isAvailableForNewContent: false
-->
{% set table = hubdb_table_rows(table_id_here) %}
{% for row in table %}
{% set firstname = row.first_name %}
{% endfor %}
And here is how I'm calling the variable in my markup:
<div class="hero">
{% include "/template_partial_file.html" %}
<h1>{{ firstname }}</h1>
</div>
You can't access a variable set inside a for loop outside of said loop.
You can set up an array outside of a loop and push information from within the loop to it, e.g.
{% set names = [] %}
{% for row in table %}
{% do names.append(row.first_name) %}
{% endfor %}

Using Jinja2 Expression within Jinja2 Statement

Let's say I have the following Jinja2 variables:
'dev_ami' = 'ami-123456'
'dev_located_ami' = 'ami-123456'
'prod_ami' = 'ami-654321'
'prod_located_ami' = 'ami-654321'
I would like to set a condition upon when the 'dev_ami' variable is equal to the 'dev_located_ami' variable. This would easily be done as shown in the following statement:
{% if dev_ami == dev_located_ami %}
... do some stuff
{% else %}
... do some other stuff
{% endif %}
But I would like to dynamically compare amis based on the deployment environment contained in a list ['dev','prod', etc...]. The following contains a templating error since there is an expression within a statement as such - {% {{ .. }} %}:
{% for env_type in ['dev','prod'] %}
{% if {{ env_type }}_ami == {{ env_type }}_located_ami %}
... do stuff
{% else %}
... do other stuff
{% endif %}
{% endfor %}
I have tried to set variables to represent the expressions I would like in the following code but unfortunately they are compiled literally as 'dev_ami' and 'dev_located_ami' whereas I would like them compiled to their corresponding variable values 'ami-123456' and 'ami-123456':
{% for env_type in ['dev','prod'] %}
{% set ami = "%s_ami"|format(env_type) %}
{% set located_ami = "%s_located_ami"|format(env_type) %}
{% if ami == located_ami %}
... do stuff
{% else %}
... do other stuff
{% endif %}
{% endfor %}
I have checked through various filters and so far have had no success. Would appreciate advice on getting this specific implementation to work properly. Thank you in advance.
I think you might be approaching the problem with the wrong datastructure in mind.
Dynamically generating variable names in order to compare amis in different environemts sounds like a massive overkill to me. Are you familiar with lists & dictionaries?
Try to start from something like this (pseudocode):
dict = { environments:
prod:
ami1: foo
ami1_located: foo
dev:
ami1: bar
ami1_located:baz
}
for env in dict[environments]:
if env[ami1] == env[ami1_located]:
[...]

Expanding variables into Jekyll Front-End

It is possible to expand a variable into a post Front-Matter?
I use a series of items for links into my template, like:
related_links:
- text: foo
link: bar
But sometimes I need to refer to other posts into my site. Normally I would use just /bar into link, but this is also used as shownotes into a podcast, I want to expand the link for http://example.com/bar. But using {% post_url YYYY-MM-DD-bar %} results into:
Error: could not read file [REDACTED]: (<unknown>): found character that cannot start any token while scanning for the next token at line 33 column 12
Any tips?
If you use
related_links:
- text: foo
link: {% post_url YYYY-MM-DD-bar %}
you will get an error because the { will start a flow style mapping and % cannot start a token in YAML. You have to put the whole scalar in (double) quotes:
related_links:
- text: foo
link: "{% post_url YYYY-MM-DD-bar %}"
What you want to do does not work because of Jekyll's pipeline:
parse YAML front matter
process rest of document with Liquid
parse result of previous step with Markdown
{% post_url YYYY-MM-DD-bar %} is a Liquid command. As you see, Liquid processes just the part of your file below the YAML front matter. Therefore, no Liquid replacement takes place there.
You can instead write something like this below the front matter:
{% assign link = post_url YYYY-MM-DD-bar %}
And then use {{link}} elsewhere. If you have multiple links, things get hacky. Something like this might work, but I am not enough of a Liquid user to know for sure:
{% capture nl %}
{% endcapture %}
{% capture rawlinks %}
{% post_url YYYY-MM-DD-bar %}
{% post_url YYYY-MM-DD-bar %}
{% endcapture %}
{% assign links = rawlinks | split nl %}
You can then specify indexes in your YAML front matter:
related_links:
- text: foo
linkindex: 0
And finally, somewhere in your document:
{{ links[related_link.linkindex] }}
YMMV if this level of uglyness is justified for your use-case.
I found a more elegant at my own:
{% assign real_link=link.link %}
{% assign link_start = real_link | slice: 0 %}
{% if link_start == "/" %}{% assign real_link = real_link | prepend: site.url %}{% endif %}
As I start al my locak links with a / to warrant that the link will be related with the root in the site, that was a better way for me.

Resources