Nette Documentation Preview

syntax
Was Sie schon immer über {iterateWhile} wissen wollten
******************************************************

.[perex]
Das Tag `{iterateWhile}` ist für verschiedene Tricks in foreach-Zyklen geeignet.

Angenommen, wir haben die folgende Datenbanktabelle, in der die Elemente in Kategorien unterteilt sind:

| id  |  catId  |  name
|------------------
| 1   |      1  | Apple
| 2   |      1  | Banana
| 3   |      2  | PHP
| 4   |      3  | Green
| 5   |      3  | Red
| 6   |      3  | Blue

Es ist natürlich einfach, Elemente in einer foreach-Schleife als Liste zu zeichnen:

```latte
<ul>
{foreach $items as $item}
	<li>{$item->name}</li>
{/foreach}
</ul>
```

Aber was ist zu tun, wenn Sie jede Kategorie in einer separaten Liste darstellen wollen? Mit anderen Worten, wie kann man die Aufgabe lösen, Elemente aus einer linearen Liste in einem foreach-Zyklus zu gruppieren. Die Ausgabe sollte wie folgt aussehen:

```latte
<ul>
	<li>Apple</li>
	<li>Banana</li>
</ul>

<ul>
	<li>PHP</li>
</ul>

<ul>
	<li>Green</li>
	<li>Red</li>
	<li>Blue</li>
</ul>
```

Wir werden Ihnen zeigen, wie einfach und elegant die Aufgabe mit iterateWhile gelöst werden kann:

```latte
{foreach $items as $item}
	<ul>
		{iterateWhile}
			<li>{$item->name}</li>
		{/iterateWhile $item->catId === $iterator->nextValue->catId}
	</ul>
{/foreach}
```

Während `{foreach}` den äußeren Teil des Zyklus markiert, d.h. die Erstellung von Listen für jede Kategorie, geben die Tags `{iterateWhile}` den inneren Teil an, d.h. die einzelnen Elemente.
Die Bedingung im End-Tag besagt, dass die Wiederholung so lange fortgesetzt wird, wie das aktuelle und das nächste Element zur selben Kategorie gehören (`$iterator->nextValue` ist das [nächste Element |/tags#$iterator]).

Wenn die Bedingung immer erfüllt ist, werden alle Elemente im inneren Zyklus gezeichnet:

```latte
{foreach $items as $item}
	<ul>
		{iterateWhile}
			<li>{$item->name}
		{/iterateWhile true}
	</ul>
{/foreach}
```

Das Ergebnis sieht dann so aus:

```latte
<ul>
	<li>Apple</li>
	<li>Banana</li>
	<li>PHP</li>
	<li>Green</li>
	<li>Red</li>
	<li>Blue</li>
</ul>
```

Wozu ist eine solche Verwendung von iterateWhile gut? Wie unterscheidet sie sich von der Lösung, die wir ganz am Anfang des Tutorials gezeigt haben? Der Unterschied besteht darin, dass die Tabelle, wenn sie leer ist und keine Elemente enthält, nicht leer dargestellt wird `<ul></ul>`.


Lösung ohne `{iterateWhile}` .[#toc-solution-without-iteratewhile]
------------------------------------------------------------------

Würden wir die gleiche Aufgabe mit ganz einfachen Konstruktionen von Template-Systemen lösen, zum Beispiel in Twig, Blade oder reinem PHP, würde die Lösung etwa so aussehen:

```latte
{var $prevCatId = null}
{foreach $items as $item}
	{if $item->catId !== $prevCatId}
		{* die Kategorie hat sich geändert *}

		{* wir schließen das vorherige <ul>, wenn es nicht das erste Element ist *}
		{if $prevCatId !== null}
			</ul>
		{/if}

		{* wir öffnen eine neue Liste *}
		<ul>

		{do $prevCatId = $item->catId}
	{/if}

	<li>{$item->name}</li>
{/foreach}

{if $prevCatId !== null}
	{* wir schließen die letzte Liste *}
	</ul>
{/if}
```

Dieser Code ist jedoch unverständlich und unintuitiv. Der Zusammenhang zwischen den öffnenden und schließenden HTML-Tags ist überhaupt nicht klar. Es ist nicht auf den ersten Blick klar, ob ein Fehler vorliegt. Und es werden Hilfsvariablen wie `$prevCatId` benötigt.

Im Gegensatz dazu ist die Lösung mit `{iterateWhile}` sauber, klar, benötigt keine Hilfsvariablen und ist narrensicher.


Bedingung im abschließenden Tag .[#toc-condition-in-the-closing-tag]
--------------------------------------------------------------------

Wenn wir im öffnenden Tag `{iterateWhile}` eine Bedingung angeben, ändert sich das Verhalten: Die Bedingung (und der Übergang zum nächsten Element) wird am Anfang des inneren Zyklus ausgeführt, nicht am Ende.
Während also `{iterateWhile}` ohne Bedingung immer eingegeben wird, wird `{iterateWhile $cond}` nur eingegeben, wenn die Bedingung `$cond` erfüllt ist. Gleichzeitig wird das folgende Element in `$item` geschrieben.

Dies ist z. B. dann nützlich, wenn Sie das erste Element in jeder Kategorie auf unterschiedliche Weise darstellen möchten, z. B:

```latte
<h1>Apple</h1>
<ul>
	<li>Banana</li>
</ul>

<h1>PHP</h1>
<ul>
</ul>

<h1>Green</h1>
<ul>
	<li>Red</li>
	<li>Blue</li>
</ul>
```

Ändern wir den ursprünglichen Code, zeichnen wir das erste Element und dann weitere Elemente aus derselben Kategorie in der inneren Schleife `{iterateWhile}`:

```latte
{foreach $items as $item}
	<h1>{$item->name}</h1>
	<ul>
		{iterateWhile $item->catId === $iterator->nextValue->catId}
			<li>{$item->name}</li>
		{/iterateWhile}
	</ul>
{/foreach}
```


Verschachtelte Schleifen .[#toc-nested-loops]
---------------------------------------------

Wir können mehrere innere Schleifen in einem Zyklus erstellen und sie sogar verschachteln. Auf diese Weise können zum Beispiel Unterkategorien gruppiert werden.

Angenommen, es gibt eine weitere Spalte in der Tabelle `subCatId` und jede Kategorie befindet sich nicht nur in einer separaten `<ul>`befindet, wird jede Unterkategorie in einer separaten `<ol>`:

```latte
{foreach $items as $item}
	<ul>
		{iterateWhile}
			<ol>
				{iterateWhile}
					<li>{$item->name}
				{/iterateWhile $item->subCatId === $iterator->nextValue->subCatId}
			</ol>
		{/iterateWhile $item->catId === $iterator->nextValue->catId}
	</ul>
{/foreach}
```


Filter |Batch .[#toc-filter-batch]
----------------------------------

Die Gruppierung von linearen Elementen erfolgt ebenfalls über einen Filter `batch` in Stapel mit einer festen Anzahl von Elementen:

```latte
<ul>
{foreach ($items|batch:3) as $batch}
	{foreach $batch as $item}
		<li>{$item->name}</li>
	{/foreach}
{/foreach}
</ul>
```

Er kann wie folgt durch iterateWhile ersetzt werden:

```latte
<ul>
{foreach $items as $item}
	{iterateWhile}
		<li>{$item->name}</li>
	{/iterateWhile $iterator->counter0 % 3}
{/foreach}
</ul>
```

{{leftbar: /@left-menu}}

Was Sie schon immer über {iterateWhile} wissen wollten

Das Tag {iterateWhile} ist für verschiedene Tricks in foreach-Zyklen geeignet.

Angenommen, wir haben die folgende Datenbanktabelle, in der die Elemente in Kategorien unterteilt sind:

id catId name
1 1 Apple
2 1 Banana
3 2 PHP
4 3 Green
5 3 Red
6 3 Blue

Es ist natürlich einfach, Elemente in einer foreach-Schleife als Liste zu zeichnen:

<ul>
{foreach $items as $item}
	<li>{$item->name}</li>
{/foreach}
</ul>

Aber was ist zu tun, wenn Sie jede Kategorie in einer separaten Liste darstellen wollen? Mit anderen Worten, wie kann man die Aufgabe lösen, Elemente aus einer linearen Liste in einem foreach-Zyklus zu gruppieren. Die Ausgabe sollte wie folgt aussehen:

<ul>
	<li>Apple</li>
	<li>Banana</li>
</ul>

<ul>
	<li>PHP</li>
</ul>

<ul>
	<li>Green</li>
	<li>Red</li>
	<li>Blue</li>
</ul>

Wir werden Ihnen zeigen, wie einfach und elegant die Aufgabe mit iterateWhile gelöst werden kann:

{foreach $items as $item}
	<ul>
		{iterateWhile}
			<li>{$item->name}</li>
		{/iterateWhile $item->catId === $iterator->nextValue->catId}
	</ul>
{/foreach}

Während {foreach} den äußeren Teil des Zyklus markiert, d.h. die Erstellung von Listen für jede Kategorie, geben die Tags {iterateWhile} den inneren Teil an, d.h. die einzelnen Elemente. Die Bedingung im End-Tag besagt, dass die Wiederholung so lange fortgesetzt wird, wie das aktuelle und das nächste Element zur selben Kategorie gehören ($iterator->nextValue ist das nächste Element).

Wenn die Bedingung immer erfüllt ist, werden alle Elemente im inneren Zyklus gezeichnet:

{foreach $items as $item}
	<ul>
		{iterateWhile}
			<li>{$item->name}
		{/iterateWhile true}
	</ul>
{/foreach}

Das Ergebnis sieht dann so aus:

<ul>
	<li>Apple</li>
	<li>Banana</li>
	<li>PHP</li>
	<li>Green</li>
	<li>Red</li>
	<li>Blue</li>
</ul>

Wozu ist eine solche Verwendung von iterateWhile gut? Wie unterscheidet sie sich von der Lösung, die wir ganz am Anfang des Tutorials gezeigt haben? Der Unterschied besteht darin, dass die Tabelle, wenn sie leer ist und keine Elemente enthält, nicht leer dargestellt wird <ul></ul>.

Lösung ohne {iterateWhile}

Würden wir die gleiche Aufgabe mit ganz einfachen Konstruktionen von Template-Systemen lösen, zum Beispiel in Twig, Blade oder reinem PHP, würde die Lösung etwa so aussehen:

{var $prevCatId = null}
{foreach $items as $item}
	{if $item->catId !== $prevCatId}
		{* die Kategorie hat sich geändert *}

		{* wir schließen das vorherige <ul>, wenn es nicht das erste Element ist *}
		{if $prevCatId !== null}
			</ul>
		{/if}

		{* wir öffnen eine neue Liste *}
		<ul>

		{do $prevCatId = $item->catId}
	{/if}

	<li>{$item->name}</li>
{/foreach}

{if $prevCatId !== null}
	{* wir schließen die letzte Liste *}
	</ul>
{/if}

Dieser Code ist jedoch unverständlich und unintuitiv. Der Zusammenhang zwischen den öffnenden und schließenden HTML-Tags ist überhaupt nicht klar. Es ist nicht auf den ersten Blick klar, ob ein Fehler vorliegt. Und es werden Hilfsvariablen wie $prevCatId benötigt.

Im Gegensatz dazu ist die Lösung mit {iterateWhile} sauber, klar, benötigt keine Hilfsvariablen und ist narrensicher.

Bedingung im abschließenden Tag

Wenn wir im öffnenden Tag {iterateWhile} eine Bedingung angeben, ändert sich das Verhalten: Die Bedingung (und der Übergang zum nächsten Element) wird am Anfang des inneren Zyklus ausgeführt, nicht am Ende. Während also {iterateWhile} ohne Bedingung immer eingegeben wird, wird {iterateWhile $cond} nur eingegeben, wenn die Bedingung $cond erfüllt ist. Gleichzeitig wird das folgende Element in $item geschrieben.

Dies ist z. B. dann nützlich, wenn Sie das erste Element in jeder Kategorie auf unterschiedliche Weise darstellen möchten, z. B:

<h1>Apple</h1>
<ul>
	<li>Banana</li>
</ul>

<h1>PHP</h1>
<ul>
</ul>

<h1>Green</h1>
<ul>
	<li>Red</li>
	<li>Blue</li>
</ul>

Ändern wir den ursprünglichen Code, zeichnen wir das erste Element und dann weitere Elemente aus derselben Kategorie in der inneren Schleife {iterateWhile}:

{foreach $items as $item}
	<h1>{$item->name}</h1>
	<ul>
		{iterateWhile $item->catId === $iterator->nextValue->catId}
			<li>{$item->name}</li>
		{/iterateWhile}
	</ul>
{/foreach}

Verschachtelte Schleifen

Wir können mehrere innere Schleifen in einem Zyklus erstellen und sie sogar verschachteln. Auf diese Weise können zum Beispiel Unterkategorien gruppiert werden.

Angenommen, es gibt eine weitere Spalte in der Tabelle subCatId und jede Kategorie befindet sich nicht nur in einer separaten <ul>befindet, wird jede Unterkategorie in einer separaten <ol>:

{foreach $items as $item}
	<ul>
		{iterateWhile}
			<ol>
				{iterateWhile}
					<li>{$item->name}
				{/iterateWhile $item->subCatId === $iterator->nextValue->subCatId}
			</ol>
		{/iterateWhile $item->catId === $iterator->nextValue->catId}
	</ul>
{/foreach}

Filter |Batch

Die Gruppierung von linearen Elementen erfolgt ebenfalls über einen Filter batch in Stapel mit einer festen Anzahl von Elementen:

<ul>
{foreach ($items|batch:3) as $batch}
	{foreach $batch as $item}
		<li>{$item->name}</li>
	{/foreach}
{/foreach}
</ul>

Er kann wie folgt durch iterateWhile ersetzt werden:

<ul>
{foreach $items as $item}
	{iterateWhile}
		<li>{$item->name}</li>
	{/iterateWhile $iterator->counter0 % 3}
{/foreach}
</ul>