SMARTY > Nested foreach loop > Overall counter - foreach

I have a nested smarty foreach loop.
I am trying to get sequentially numbered output on the divs ( see example )
Using the key or index or .iteration on the inner array doesn't work the way I want.
I can see what's happening, but I want some way of keeping an overall running count, rather than a partial count, that keeps resetting on every branch of the outer loop.
I have tried numerous things without success.
Can anyone help ? Much appreciated.
{foreach from=$children item='child'}
{if $child.show_in_menu}
{* loop through grandchildren *}
{foreach from=$child item='grandchild' name='grandchildrenpages' key=k}
{if $grandchild.show_in_menu}
<div class="view-{$k}"></div>
{/if}
{/if}
{/foreach}
{/if}
{/foreach}
Desired output
<div class="view-1"></div>
<div class="view-2"></div>
<div class="view-3"></div>
<div class="view-4"></div>
<div class="view-5"></div>
<div class="view-6"></div>
<div class="view-7"></div>
<div class="view-8"></div>
Currentoutput
<div class="view-0"></div>
<div class="view-1"></div>
<div class="view-2"></div>
<div class="view-1"></div>
<div class="view-2"></div>
<div class="view-5"></div>
<div class="view-6"></div>
<div class="view-7"></div>

Use {counter}:
{foreach from=$children item='child'}
{if $child.show_in_menu}
{foreach from=$child item='grandchild' name='grandchildrenpages' key=k}
{if $grandchild.show_in_menu}
<div class="view-{counter}"></div>
{/if}
{/foreach}
{/if}
{/foreach}
(btw, your example has one {/if} more than needed, I guess it's a typo

Related

limiting results of foreach (getting only 3 results) using polymer

I'm trying to limit foreach item. here it is my source :
<div class="build-failed">
<h1 class="jenkins-status"><span data-bind="title"></span> FAILED</h1>
<ul class="list-nostyle list-failed">
<li data-foreach-item="failedJobs">
<div class="label" data-bind="item.label"></div>
<div class="value" data-bind="item.value"></div>
</li>
</ul>
</div>
<div class="build-succeeded">
<h1 class="jenkins-status">All <span data-bind="title"></span> builds are successful</h1>
<i class="fa fa-thumbs-o-up"></i>
</div>enter code here
<p class="updated-at" data-bind="updatedAtMessage"></p>
and I want to get only 3 results. I know that I have to add something in "data-foreach-item" but I don't know what is it.
With <iron-list>, your <ul> can be rewritten as
<ul>
<iron-list items="[[failedJobs]]">
<template>
<li>
<div class="label">[[item.label]]</div>
<div class="value">[[item.value]]</div>
</li>
</template>
</iron-list>
</ul>
Try and see if the property, maxPhysicalCount, can get you only three results ;)
I thought I would find an applicable filter in the documentation:
http://batmanjs.org/docs/filters.html
But I couldn't find one! first returns only one item and truncate works for strings only, so neither of those would work.
You can create your own filter:
https://www.softcover.io/read/b5c051f3/batmanjs_mvc_cookbook/html#sec-custom_filter
For example, to limit an array to three items:
Batman.Filters.limit = (array, limit) -> array?.slice(0, limit)
Then, use it in your binding:
<li data-foreach-item="failedJobs | limit 3">...</li>
(Hmm, I hope data-foreach works with filters!)
Anyhow, hope it helps :)

Creating menu logic with Thymeleaf

I'm trying to dynamically create a menu using basic logic, something like this.
List item
List item
List item
List item
List item
I made this code
<ul>
<div data-th-each="field, iter : ${fields}" data-th-remove="tag">
<div data-th-if="${field.text} != null" data-th-switch="${field.href}" data-th-remove="tag">
<li data-th-case="null" data-th-utext="${field.text}" >
<li data-th-case="*"><a data-th-href="${field.href}" data-th-utext="${field.text}" ></a>
</div>
<ul data-th-if="${field}" class="sub-menu">
<div data-th-each="prop, propIter : ${field.sub_items.sub_item.properties}" data-th-remove="tag">
<div data-th-if="${prop.text} != null" data-th-switch="${prop.href}" data-th-remove="tag">
<li data-th-case="null" data-th-utext="${prop.text}"></li>
<li data-th-case="*"><a data-th-href="${prop.href}" data-th-utext="${prop.text}"></a></li>
</div>
</div>
</ul>
</li>
</div>
</ul>
But it returns parsing errors, I think it's mostly a Thymeleaf/HTML problem.
It's probably because of the unclosed "li" tags in the switch statement but I'm not sure how to fix it.
Right, it has to be valid html before processing. You can't do any kind of tricks like you have above, even if the output would be valid html.
I think you should be able to restructure your html to look like this:
<ul>
<th:block data-th-each="field, iter : ${fields}" data-th-if="${field.text} != null">
<li>
<span data-th-if="${field.href == null}" data-th-utext="${field.text}" />
<a data-th-unless="${field.href == null}" data-th-href="${field.href}" data-th-utext="${field.text}" />
<ul data-th-if="${field}" class="sub-menu">
<th:block data-th-each="prop, propIter : ${field.sub_items.sub_item.properties}" data-th-if="${prop.text} != null">
<span data-th-if="${prop.href == null}" data-th-utext="${prop.text}" />
<a data-th-unless="${prop.href == null}" data-th-href="${prop.href}" data-th-utext="${prop.text}" />
</th:block>
</ul>
</li>
</th:block>
</ul>
I've never though about using data-th-remove="tag" like you have. But I think you should be using <th:block> instead for cases like this.

Thymeleaf: How to set a list as a result of a switch statement

I'm using Thymeleaf in a Spring project, and I need to show a list, as a result of a one of the cases, but I don't know how.
This is the code:
<!--Global validation results-->
<div th:if="${#fields.hasErrors('global')}">
<div class="alert alert-danger" role="alert"
th:each="err : ${#fields.errors('global')}">
<div th:switch="${err}">
<div th:case="error.fromAfterTo" th:text="#{error.fromAfterTo}"></div>
<div th:case="error.overlaps" th:text="#{error.overlaps}">
<ul th:each="interval : ${dateOverlaps}">
<li th:text="${#temporals.format(interval.datefrom, 'dd/MM/yyyy')} +
' - ' + ${#temporals.format(interval.dateto, 'dd/MM/yyyy')}">
</li>
</ul>
</div>
</div>
</div>
th:case="error.overlaps" works, but the list just appears, when setting it outside the switch statement.
Thanks in advance for your help.
Aleix
The th:text attribute, which evaluates #{error.overlaps}sets the result of this evaluation as the body of the div tag it is in, effectively substituting your loop with the evaluation result. That is why you see the list outside of the switch.
Details here.
can you substitute
th:case="error.overlaps"
with
th:case="#{error.overlaps}"
and let me know if this worked for you
This is the final code, that's working as expected:
<!--Global validation results-->
<div th:if="${#fields.hasErrors('global')}">
<div class="alert alert-danger" role="alert"
th:each="err : ${#fields.errors('global')}">
<div th:switch="${err}">
<div th:case="error.fromAfterTo" th:text="# error.fromAfterTo}"></div>
<div th:case="error.overlaps">
<p th:text="#{error.overlaps}"></p>
<ul th:each="interval : ${dateOverlaps}">
<li th:text="${#temporals.format(interval.datefrom, 'dd/MM/yyyy')}
+ ' - ' + ${#temporals.format(interval.dateto, 'dd/MM/yyyy')}">
</li>
</ul>
</div>
</div>
</div>
</div><!--Global validation results-->
Thanks once more for your help.

Dust templating, check if iteration is divisible by a number

Trying to check to see if an iteration is divisible by a number, and wrap it in a <div> if it is, but I can't seem to get it to work. Is there even a way to do this with Dust?
{#sitemap.items}
{#if cond="$idx % 2"}
<div class="row">
{/if}
<div class="sitemap-column col-6">
{#.}
//do stuff with the object
{/.}
</div>
{#if cond="sitemap.count % 2"}
</div>
{/if}
{/sitemap.items}
The easiest way is to use the math helper like this:
{#items}
{#math key=$idx method="mod" operand=2}
{#eq value=0}<div class="row">{/eq}
{/math}
{/items}

How can stop foreach an div class in smarty2 template

This is my code and I need stop foreach the last ul and tab-content permanently I use a smarty 2 I have try everything and I can not resolve it.
<div class="tabs">
<ul class="nav nav-tabs">
{foreach from=$languages item=v}
<li>
Example
</li>
// --> I Want stop this two
<ul>
<div class="tab-content">
// I Want stop this two <---
<div class="tab-pane fade" id="tab_1">
<p>Example text</p>
</div>
</div>
{/foreach}
</div>
I Have try this but is not working
{$data = [1,2,3,4,5]}
{foreach $data as $value}
{if $value == 3}
{* abort iterating the array *}
{break}
{/if}
{$value}
{/foreach}
{*
prints: 1 2
*}
What you should do is to simple assign selected data in PHP (in your example not 5 elements but 2 elements) to Smarty and simple display data in Smarty
Smarty template file:
{foreach from=$data item=value}
{$value}
{/foreach}
And in PHP file not:
$smarty->assign('data',array(1,2,3,4,5));
but
$smarty->assign('data',array(1,2));
However if you cannot change assigned data from PHP (or it comes from other system) you can simple loop for all elements but display only for example 2 first as below:
{foreach from=$data item=value name=data}
{if $smarty.foreach.data.iteration le 2}
{$value}
{/if}
{/foreach}

Resources