How to do a foreach loop in a Twig - twig

Here i have attached screenshot,in that 2nd section 2 rows are present. i need to display only one row with custom code condition, If i disable from admin side,it will work correctly,but i need loop condition for enable and disable to display only row. Here is my code,
<div class="col-md-12" >{% for module in modules %}<div class="img-responsive">
{{ module }}
{% endfor %}</div></div>
</div>

There's special loop variables inside a loop that let's you keep track of index and more. In your case loop.index.
<div class="col-md-12" >
{% for module in modules %}
<div class="img-responsive">
{# Replace 1 with a specific index you want to use as condition #}
{% if loop.index == 1 %}
{{ module }}
{% else %}
No module
{% endif %}
</div>
{% endfor %}
</div>

Related

A For Loop in Jinja can't be used again or how to move First

When reusing the same SQLAlchemy Result to iterate it only works the first time.
See the below how I get all the qual.workforce but none of the displayname, busunit or certcount's:
<ul class="empltype">
{% for qual in allquals %}
<li>{{qual.workforce}}</li>
{% endfor %}
</ul>
<ul class="names">
{% for qual in allquals %}
<li>{{qual.displayname}}</li>
{% endfor %}
</ul>
<ul class="busunit">
{% for qual in allquals %}
<li>{{qual.busunit}}</li>
{% endfor %}
</ul>
<ul class="certcount">
{% for qual in allquals %}
<li>{{qual.certcount}}</li>
{% endfor %}
I would like to MoveFirst before the 3 loops for displaynames, busunit and certcount so they all work.
I don't want have 4 copies of the same variable (allquals1,2,3) even though I know that will work. I'm guessing the jinja render engine only iterates through objects once, is there a way to tell it to iterate over the same result set each time its used in a loop?
it happens just because the result is a generator, and it's values can be accessed only once. you have to do allquals = list(query_result) to iterate multiple times over it

Is there a way to programmatically have 4 cards per row?

I am currently working with Python Flask and Bootstrap.
I am looking to get it so that if there are 4 cards in one row, it will automatically create a new row.
Issue i am having just now is the more posts I have the longer and thinner the rows cards get.
Current code:
{% extends "base.html" %}
{% block content %}
<div class="card-deck">
{# Go through each forum post #}
{% for post in forum_posts.items %}
<div class="card">
<div class="card-body">
<span class="badge badge-info">{{ post.cat }}</span>
<h3 class="card-title"><a class="card-title"
href="{{ url_for('forum_posts.view_post', forum_post_id=post.id) }}">{{ post.title }}</a>
</h3>
<h6 class="card-subtitle mb-2 text-muted">Written by: {{ post.author.username }}</h6>
<p>{{ post.text[:100] }}...</p>
</div>
<div class="card-footer">
<a href="{{ url_for('forum_posts.view_post', forum_post_id=post.id) }}"
class="btn btn-primary">Read
Blog Post</a>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
You could code this on the python side so that it makes it easier in jinja2, using an array of arrays:
>>> arr = [0,1,2,3,4,.....,102]
>>> forum_posts.items = []
>>> for i in range(int(len(arr)/4)):
j = i * 4
forum_posts.items.append([arr[j], arr[j+1], arr[j+2], arr[j+3]])
# needs an error trap for IndexError on 103
Then in jinja2: you can double loop:
{% for row in forum_posts.items %}
{% for item in row %}
{# HTML here for a new row of at most 4 cards #}
There is a way of doing the same kind of thing in jinja2 using variable loop counters and setting new row HTML if for example the new loop index is an exact multiple of 4:
{% for i, post in enumerate(forum_posts.items) %}
{% if i % 4 == 0 %}
{# new row code #}
{% else %}
{# regular row code %}
{% endif %}
{% endfor %}

A solution for grouping items in loop with Timber and Twig

Often i need to do some tricky layout on dynamic elements like galleries.
Here's one example:
<ul>
<li class="slide">
<img src="img_01.jpg">
<img src="img_02.jpg">
</li>
<li class="slide">
<img src="img_03.jpg">
<img src="img_04.jpg">
</li>
<li class="slide">
<img src="img_05.jpg">
<img src="img_06.jpg">
</li>
</ul>
I've managed to do it with the following snippet. But i wanted some suggestions if possible about how to make it more flexible or more simple, like grouping by any number. Maybe using cycle() or any other method. I was getting strange results using the slice() or array[1:2] notation.
<ul>
{% for image in gallery %}
{% set current = loop.index %}
{% set next = current + 1 %}
{% if current is odd %}
<li class="slide">
{% for image in gallery %}
{% if loop.index in [current,next] %}
{% set th = TimberImage(image) %}
<img src="{{th.src}}">
{% endif %}
{% endfor %}
</li>
{% endif %}
{% endfor %}
</ul>
Any suggestions are welcomed.
Timber becomes very handy for quick in and out fixes with Timber::compile or custom themes with full routing. The purpose of the question is to create some snippet that can be reused.
Kudos to creators.
https://github.com/timber/timber
You can approach with the rest of the division with the following code (Here a working solutions):
{# number of element for every section #}
{% set section = 2%}
<ul>
{% for image in gallery %}
{% if loop.index % section == 1 %}
<li class="slide">
{% endif %}
{% set th = TimberImage(image) %}
<img src="{{th.src}}">
{% if loop.index % section == 0 or loop.last %}
</li>
{% endif %}
{% endfor %}
</ul>
You can easily reuse this code making a Twig macro using as parameter the gallery and the number of element for section (highlighted with the variable section
Here's the final result taking the suggestion of #Matteo for a macro:
https://gist.github.com/lithiumlab/5ee0454b0a77b1cc26fc0ce8ba52fd80
views/single.twig:
{% import 'utils.twig' as utils %}
{{utils.group_collection(gallery,3)}}
views/utils.twig:
{% macro group_collection(collection, groupby) %}
{% set section = groupby|default(2) %}
<ul>
{% for element in collection %}
{% if loop.index % section == 1 %}
<li class="group">
{% endif %}
{% set th = TimberImage(element) %}
<img src="{{th.src}}">
{% if loop.index % section == 0 or loop.last %}
</li>
{% endif %}
{% endfor %}
</ul>
{% endmacro %}

Use loop.index as part of template name to include with Twig?

I have an array of 3 items so in the following I'm including sub-component.twig 3 times:
{% for i in array %}
<div class="my-class">
{% include "sub-component.twig" %}
</div>
{% endfor %}
However I actually have 3 slightly different templates and I would like to load a different one for each iteration over the array:
sub-component-1.twig
sub-component-2.twig
sub-component-3.twig
When I print loop.index in the template the result is "1", "2" and "3". Can I therefore use the index to form the template name?
{% for i in array %}
<div class="my-class">
{{ loop.index }}
{% include ["sub-component-" ~ loop.index ~ ".twig"] %}
</div>
Possibly because I'm using gulp twig I had to break things out into variables for this to work.
https://github.com/zimmen/gulp-twig
{% for i in array %}
<div class="my-class">
{% set sub-component_1 = "sub-component-" %}
{% set sub-component_2 = loop.index %}
{% set sub-component_3 = ".twig" %}
{% set sub-component_full = sub-component_1 ~ sub-component_2 ~ sub-component_3 %}
{% include sub-component_full %}
</div>
{% endfor %}

Twig execute a function once instead of 3 times

I was wondering if it is possible to create some sort of condition which can be used on 3 different places in a template with Twig.
Let's say I have 3 slider images with a link. A user of the template has the option to choose between a button link or a normal link via a dropdown menu. Like so (below is only the first slider):
{% if theme.slide1 %}
<li class="animate-in f1">
<div class="wrap">
{{ 'Read more' | t }}
</div>
</li>
{% endif %}
{% if theme.slide2 %}
<li class="animate-in f2">
<div class="wrap">
{{ 'Read more' | t }}
</div>
</li>
{% endif %}
Normally you would do something like:
{% if theme.slide1_link_setting == 'Link' %} do this {% else %} do that {% endif %}
You have to do this 3 times if you have 3 slider images. But what if you have eg. 10 slider images?
I tried to create a function which checks if a setting is a button or normal link.
{% set link_style = theme.slide1_link in ['link', 'button'] ? 'normal-link': 'btn btn-custom-2 btn-sequence' %}
First of all the function above doesn't work.
Second I don't know how to set the number of the slide you're in. I want something like below:
{% set link_style = theme.slide[numberOfSlide]_link in ['link', 'button'] ? 'normal-link': 'btn btn-custom-2 btn-sequence' %}
Is there anybody who can help me with this?

Resources