Liquid template - Differentiate between null and empty nodes - maps

I am using liquid template in my LogicApp for data transformation. I need to differentiate if a json node is empty, null.
So in json if i have "Name":"" "Name":null , then I need to differentiate between them. I observed that all the below 3 conditions(== "" , == empty == blank) return true for both of these cases. So how I explicitly check if it is null or just ""
{% if content.Name == "" %}
{% endif %}
{% if content.Name == empty %}
{% endif %}
{% if content.Name == blank %}
{% endif %}

Related

Using Liquid, is there a way to filter an array and ignore non matching items

Using Liquid for a store.
I want to look through an array of values and check to see if any of those values match another list of values. If they match i want to display them. if they do not match i want to ignore them.
I'm currently able to do it in reverse by looking at all the values then 'remove' the ones i don't want individually but that is a terrible way to do this.
{% for 'field' in [metafield.key.value] | split: ", " %}
{% if field == 'value 1' or field == 'value 2' or field == 'value 3'%}
<div>
field
</div>
{% else %}
{% continue %}
{% endif %}
for future weary travelers:
this works you may need to adjust where you're splitting the string:
{% assign metafield_str = product.metafields.yada.yada | split: "," %}
{% assign control_str = 'value, something, test, test2' | split: "," %}
{%- capture variable -%}
{% for c_str in control_str %}
{% for m_str in metafield_str %}
{% if c_str == m_str %}
{{m_str}}
{% endif %}
{% endfor %}
{% endfor %}
{%- endcapture -%}

How can I loop an ansible task with script module with jinja code

I have an ansible task where I want to execute script.sh based on condition. My problem is, when I test my task with debug module, the jinja {% for %} for loop works fine, but when i put the jinja code inside script module, the for loop not work. The task execute only the first iteration and stopped.
Anyone can tell me where is the error in my code?
task:
- name: Exec script
script: "{% set tmp_list = [] %}
{% for i in list_a %}
{% set search = namespace(found=False) %}
{% for j in list_b %}
{% if i[l] == j[0] %}
{% set search.found = True %}
{% if i[2] not in j %}
Script1.sh
{% endif %}
{% endif %}
{% endfor %}
{% if not search.found and i[1] not in tmp_list %}
{% do tmp_list.append(i[1]) %}
Script2.sh
{% elif not search.found and i[1] in tmp_list %}
Script1.sh
{% endif %}
{% endfor %}"
args:
executable: /bin/sh

How do I create an array from a forloop?

I have a folder of images that I'd like to render on a page. I'd like these images to be ordered/filtered a particular way. To do that, I understand that the images need to first be together in an array.
I therefore start with an empty array:
{% assign my_array = "" %}
I then loop through the image folder, and attempt different ways of pushing each image into my_array. Example:
{% for image in site.static_files %}
{% if image.path contains "assets/images/target-folder" %}
<!-- Push image into array -->
{{ my_array | push: image }}
{% endif %}
{% endfor %}
Ideally, I can then use this array as intended:
{% for image in my_array | sort:"date" | reverse %}
<!-- show image -->
{% endfor %}
I'm aware that I could make a data file with the images, but I'd like to avoid needing to take that extra step. Thanks for reading.
You are almost there, the way of how you are creating the array it is the only thing to fix.
This {% assign my_array = "" %} creates an empty string. One easy way to create an array in Liquid is to split the above:
{% assign my_array = "" | split: ',' %}
Now you can push items into the array inside a for loop in the following way:
{% for image in site.static_files %}
{% if image.path contains "assets/images/target-folder" %}
<!-- Push image into array -->
{% assign my_array = my_array | push: image %}
{% endif %}
{% endfor %}
Also note that you can do this without a loop using where/where_exp filters:
{% assign my_array = site.static_files |
where_exp: "item", "item.path contains 'assets/images/target-folder'" %}
or:
{% assign target_folder = "assets/images/target-folder" %}
{% assign my_array = site.static_files |
where_exp: "item", "item.path contains target_foler" %}
(Although, unlike the accepted answer, this doesn't precisely correspond to the question's title, it's still a useful option in the described example.)
This solution worked for me:
{% assign namesArr = '' %}
{% for animal in animals %}
{% assign namesArr = namesArr | append: animal.name %}
{% if forloop.last == false %}
{% assign namesArr = namesArr | append: "," %}
{% endif %}
{% endfor %}
{% assign namesArr = namesArr | split: "," %}
Now namesArr is array, we can check array contains some value: https://stackoverflow.com/a/30823063/5638975

Jekyll forloop.last --> before last?

I made a dummy "related posts" in Jekyll 3.2.1 with the following solution:
{% for post in site.posts limit: 4 %}
{% if page.author == post.author and page.title != post.title %}
<div class="post-stream-item">
<a href="{{ post.url | prepend: site.baseurl }}" title="{{ post.title }}"><div class="post-stream-content">
<img src="{{ post.thumbnail }}" width="80" height="auto" /><span class="post-stream-item-meta"><h3>{{ post.title }}</h3><p>{{ post.author }} on {{ post.date | date: "%b %-d, %Y" }} • {% assign words = post.content | number_of_words %}
{% if words <= 160 %}
1 min
{% else %}
{{ words | plus: 159 | divided_by:160 }} mins
{% endif %} read</p></span></div></a></div>{% if forloop.last == false %}<hr>{% endif %}
{% endif %}
{% endfor %}
The for loop iterates through the posts list in the site and gives
it a limit
If the author of the current post is the same as the author of the
iterated post, but the title is not the same, then it fills out the
jinja bindings.
The problem is with the {% if forloop.last == false %}<hr>{% endif %} part, cause if there is more iterable (post) in the forloop, it will display the <hr> tag, even if it's the last element shown to the user.
Is there any attribute to refer to the penultimate element of the list or any better solution to this?
There isn't going to be a simple out-of-the-box one-line solution for this. Think about it this way: you're essentially asking for a feature that looks ahead in time and figures out whether this is the last time the if statement will evaluate to true. Jekyll is great, but it can't predict the future!
You could do this yourself by using two loops: one that loops through and counts how many <hr> elements you should show. Then another that actually prints stuff out, checking against the count you came up with to decide whether to print the <hr> element.
Or you could just use CSS to hide the last <hr> element. Google is your friend here.
Print a certain number of posts with no print condition
Solution : use loop limit
{% for post in site.posts limit: 4 %}
... output code here
{% endfor %}
You will print exactly 4 posts and forloop.last always works.
Print a certain number of posts with a print condition in the loop
Solution : use where filter, a counter and break
Now that you include a conditional printing :
you don't know which and how many posts will be printed.
if you don't print last post, you have an HR at the end of your list.
If you want to know how many posts you can print, you can use {% assign authorsPosts = site.posts | where: "author", page.author %} and authorsPosts.size.
This code will do it nicely, even if available posts number is less than your limit.
{% comment %} +++++ Max number of posts to print +++++ {% endcomment %}
{% assign limit = 4 %}
{% comment %} +++++ Select authors posts +++++{% endcomment %}
{% assign authorsPosts = site.posts | where: "author", page.author %}
{% comment %} +++++ If author's Posts number is less than limit, we change the limit +++++ {% endcomment %}
{% if limit >= authorsPosts.size %}
{% comment %} +++++ Number of "listable" posts is author's posts number less 1 (the one actually printed) +++++ {% endcomment %}
{% assign limit = authorsPosts.size | minus: 1 %}
{% endif %}
{% assign postsCounter = 0 %}
{% for post in authorsPosts %}
{% if page.author == post.author and page.title != post.title %}
{% assign postsCounter = postsCounter | plus: 1 %}
<h3>{{ post.title }}</h3>
{% comment %} +++++ Prints hr only if we are not printing the last post +++++ {% endcomment %}
{% if postsCounter < limit %}<hr>{% endif %}
{% comment %} +++++ Exit for loop if we reached the limit +++++ {% endcomment %}
{% if postsCounter == limit %}{% break %}{% endif %}
{% endif %}
{% endfor %}

How to add a new index to an existing array on Volt?

So I have an existing array, I want to run a for loop through it and recreate new arrays. I am trying to figure out how to create my own array directly on volt. Here is my code:
{% set oNomesAgendaAmigos = [], oNomesAgendaRecomendado = [], oNomesAgendaAmigosRecomendado = [] %}
{% for oNomeAgenda in oNomesAgenda %}
{% set oNomesAgendasTotal = oNomeAgenda.cliente_nome %}
{% if oNomeAgenda.ind_amigo == 1 %}
{% set oNomesAgendaAmigos = oNomeAgenda %}
{% endif %}
{% if oNomeAgenda.ind_recomendado == 1 %}
{% set oNomesAgendaRecomendado = oNomeAgenda.cliente_nome %}
{% endif %}
{% if oNomeAgenda.ind_recomendado == 1 AND oNomeAgenda.ind_amigo == 1 %}
{% set oNomesAgendaAmigosRecomendado = oNomeAgenda.cliente_nome %}
{% endif %}
{% endfor %}
Last time i have checked there were no mechanism for setting table bit by bit in Volt. The walk-around would be to use array_merge() or implement own filter/method into Volt engine.
Anyway it's a bit against MVC principles. You should set all tables you need over your PHP part of code.
To loop ever array with indexes inside loop you use that trick:
{% for index, value in numbers %}
{{ index }}: {{ value }}
{% endfor %}
I also really appreciate this part of Volt Documentation.

Resources