Jinja2 for loop behaving similarly to with - jinja2

I'd like to iterate over a set of objects and find the maximum of one particular attribute, however jinja2 ignores any action within an iterator on a variable declared outside of the iterator. For example:
{% set maximum = 1 %}
{% for datum in data %}
{% if datum.frequency > 1 %}
{% set maximum = datum.frequency %}
{% endif %}
{% endfor %}
{# maximum == 1 #}
datum.frequency is definitely greater than 1 for some datum in data.
EDIT (solution)
This is similar to this post, but there's a bit more to it. The following works and is very ugly.
{% set maximum = [1] %}
{% for datum in data %}
{% if datum.freq > maximum[-1] %}
{% if maximum.append( datum.freq ) %}{% endif %}
{% endif %}
{% endfor %}
{% set maximum = maximum[-1] %}

Have you considered writing a custom filter to return the highest value of a particular attribute within your collection? I prefer to minimize the amount of logic I use in Jinja2 templates as part of maintaining a 'separation of concerns'.
Here is a link to a very good example of how one can be written in python:
Custom jinja2 filter for iterator
Once you have your filter returning the value you need access it by using '|' like so:
{% set maximum = datum|filtername %}

Related

For loop in Shopify not working over number 9

I'm having an issue with a for loop in Shopify. I'm sure it used to work, but I can't get it to work over the number 9 now.
{% assign productTag1 = Availability14 %} (in this example, the product has only 1 tag, which is Availability14)
{% assign avail_stop = false %}
{% for j in (0..15) %}
{% assign check_avail = 'Availability' | append:j %}
{% if productTag1 contains check_avail %}
{% assign avail_stop = true %}
{% capture tag_name %}{{check_avail}}{% endcapture %}
{% break %}
{% endif %}
{% endfor %}
{% if avail_stop %}
{% assign availability = check_avail | remove:'Availability' | plus:0 %}
{% endif %}
At the moment, I'm returning 1, not 14. I imagine it's something to do with the fact 14 includes a 1, but I can't wrap my head around it.
Any help is appreciated.
You have a {% break %} statement in your if. Once the if becomes true it will exit the loop instantly.
If you want to skip the next code you must use {% continue %} not {% break %}.
On my mind this is an issue with conditional operator. As you said, 14 contains 1, so why not simply use strict conditional operator like this:
{% if productTag1 == check_avail %}
{% assign has_stop = true %}
{% break %}
{% endif %}
(or did I miss something?)

jinja2 using {if} within {for}

I'm trying to make a template which iterates over a list to check if a string exists. if it does then something happens, if the string isn't in the list, something else should happen. The issue is the result is repeated for all the lines in the list, which i do not want.
e.g.
The list is some simple yaml
LIST:
- A
- B
- C
Jinja looks like
{% for line in mylist %}
{% if 'A' in line %}
{{ A }} Was found in the list
{% else %}
{{ A }} Was not found
{% endif %}
{% endfor %}
So when 'A' matches i get this
A Was found in the list
A Was not found
A Was not found
And when 'A' does not match i get this:
A Was not found
A Was not found
A Was not found
Basically i need to stop it iterating over the list and just do one thing if it matches or one thing if it doesn't match
So if 'A' matches i need it to just do
A was found
If 'A' doesn't match i need it to just do A was not found
Use some kind of flag variable:
{% set ns = namespace(found=false) %}
{% for line in mylist %}
{% if 'A' in line %}
{% set ns.found=true %}
{% endif %}
{% endfor %}
{% if ns.foo %}
{{ A }} Was found in the list
{% else %}
{{ A }} Was not found
{% endif %}

Jinja & Wtforms- check if html attribute has been defined

Let's say I have a form with a hundred fields. Some of them have description defined:
i.e. Sales=IntegerField('Sales', description='Annual Sales')
some of them do not:
i.e. Name=TextField('Full Name')
in Jinja, how can I check whether description has been set or not?
I've tried
{% for field in form %}
{% if field.description != None %}
<h2>{{field.description}}</h2>
{{field.label}}
{{field}}
{% endif %}
{% endfor %}
I'm trying to iterate through the fields, and create an html header to group the fields into sections.
I was also doing
{%set currDesc="nothing"%}
{%for field in form %}
{% if field.description != currDesc %}
<h2>{{field.description}}</h2>
{% set currDesc= field.description %}
{% endif %}
{% endfor %}
but it ends up creating a ton of <h2>s
upon further research, we can check whether an attribute is defined explicitly in wtforms by using an empty string comparison:
{% if field.description =! '' %}
<h2>{{field.description}}</h2>
{% endif %}

How to increment the counter inside a Liquid for loop?

I am struggling to figure out how to increment the index variable within a for loop in Liquid/Jekyll. Currently, I have something along the lines of
{% for i in (0..num_posts) %}
{% if i < some_value %}
do_thing
{% else %}
{% endif %}
{% assign i = i|plus:1 %}
{% if i<some_value %}
do_another_thing
{% else %}
{% endif %}
{% endfor %}
The problem is, instead of incrementing i, it leaves i as the same value.
Things I have tried:
Using {% assign i = i|plus:1 %}.
Using {% increment i %}.
Using
{% assign j = i|plus:1 %}
{% assign i = j %}
I can't use the offset command either since the code doesn't always check only 2 if statements in the loop.
Any ideas?
Here i is not the index.
To get the current index use {{ forloop.index }}.
{% if forloop.index < 5 %}
Do something
{% endif %}
To assign your own custom index inside a loop you may use something like:
{% assign i = 0 %}
{% for thing in things %}
{% assign i = i | plus:1 %}
{% endfor %}
Just use
{% increment my_counter %}
Creates a new number variable, and increases its value by one every time it is called. The initial value is 0. Also works with decrement. But just if you only have one simple counter, can't reset and always starts at "0"

Is there a way in Liquid to use the contains operator to check for an exact match?

When searching an array for a match in a Liquid template, how do you call contains exactly? For example, if tag of a page may contain separable or non-separable, how do you find the pages that contain only the separable and not the non-separable tag? In my experience, the {% if post.tags contains 'separable' %} statement considers both cases.
Refer to the documentation you can use this filter
{% assign tags = post.tags | where:"tag","separable" %}
Loop through the array and check the values with a match operator. If it matches change a variable from false to true:
{% assign found_seperable = false %}
{% for tag in post.tags %}
{% if tag == 'separable' %}
{% assign found_seperable = true %}
{% endif %}
{% endfor %}
Then check the variable:
{% if found_seperable %}
do what you want if true
{% else %}
do what you want if false
{% endif %}