Nette Documentation Preview

syntax
Tot ce ați vrut să știți despre {iterateWhile}
**********************************************

.[perex]
Eticheta `{iterateWhile}` este potrivită pentru diverse trucuri în ciclurile foreach.

Să presupunem că avem următorul tabel de bază de date, în care articolele sunt împărțite în categorii:

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

Desigur, este ușor să desenezi elementele dintr-o buclă foreach sub forma unei liste:

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

Dar ce să faceți dacă doriți să redați fiecare categorie într-o listă separată? Cu alte cuvinte, cum să rezolvați sarcina de a grupa elementele dintr-o listă liniară într-un ciclu foreach. Rezultatul ar trebui să arate astfel:

```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>
```

Vă vom arăta cât de ușor și elegant poate fi rezolvată această sarcină cu iterateWhile:

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

În timp ce `{foreach}` marchează partea exterioară a ciclului, adică întocmirea listelor pentru fiecare categorie, etichetele `{iterateWhile}` indică partea interioară, adică elementele individuale.
Condiția din tag-ul end spune că repetiția va continua atâta timp cât elementul curent și cel următor aparțin aceleiași categorii (`$iterator->nextValue` este [elementul următor |/tags#$iterator]).

Dacă condiția este întotdeauna îndeplinită, atunci toate elementele sunt desenate în ciclul interior:

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

Rezultatul va arăta astfel:

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

La ce este bună o astfel de utilizare a iterateWhile? Prin ce diferă de soluția pe care am arătat-o la începutul acestui tutorial? Diferența constă în faptul că, dacă tabelul este gol și nu conține niciun element, nu se va afișa gol `<ul></ul>`.


Soluție fără `{iterateWhile}` .[#toc-solution-without-iteratewhile]
-------------------------------------------------------------------

Dacă am rezolva aceeași sarcină cu sisteme de șabloane complet de bază, de exemplu în Twig, Blade sau PHP pur, soluția ar arăta cam așa:

```latte
{var $prevCatId = null}
{foreach $items as $item}
	{if $item->catId !== $prevCatId}
		{* categoria s-a schimbat *}

		{* închidem pagina anterioară <ul>, dacă nu este primul element *}
		{if $prevCatId !== null}
			</ul>
		{/if}

		{* vom deschide o nouă listă *}
		<ul>

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

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

{if $prevCatId !== null}
	{* închidem ultima listă *}
	</ul>
{/if}
```

Cu toate acestea, acest cod este de neînțeles și neintuitiv. Legătura dintre etichetele HTML de deschidere și închidere nu este deloc clară. Nu este clar la prima vedere dacă este vorba de o greșeală. Și este nevoie de variabile auxiliare precum `$prevCatId`.

În schimb, soluția cu `{iterateWhile}` este curată, clară, nu are nevoie de variabile auxiliare și este infailibilă.


Condiția din eticheta de închidere .[#toc-condition-in-the-closing-tag]
-----------------------------------------------------------------------

Dacă specificăm o condiție în tag-ul de deschidere `{iterateWhile}`, comportamentul se schimbă: condiția (și avansarea la elementul următor) este executată la începutul ciclului interior, nu la sfârșitul acestuia.
Astfel, în timp ce `{iterateWhile}` fără condiție este introdus întotdeauna, `{iterateWhile $cond}` este introdus doar atunci când este îndeplinită condiția `$cond`. În același timp, următorul element este scris în `$item`.

Acest lucru este util, de exemplu, în situația în care doriți să redați primul element din fiecare categorie într-un mod diferit, cum ar fi:

```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>
```

Să modificăm codul original, desenăm primul element și apoi elementele suplimentare din aceeași categorie în bucla interioară `{iterateWhile}`:

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


Bucle imbricate .[#toc-nested-loops]
------------------------------------

Putem crea mai multe bucle interioare într-un ciclu și chiar le putem anina. În acest fel, de exemplu, se pot grupa subcategorii.

Să presupunem că există o altă coloană în tabelul `subCatId` și, pe lângă faptul că fiecare categorie se află într-o coloană separată `<ul>`, fiecare subcategorie va fi într-o coloană separată `<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}
```


Filtru |batch .[#toc-filter-batch]
----------------------------------

Gruparea elementelor liniare este, de asemenea, asigurată de un filtru `batch`, în loturi cu un număr fix de elemente:

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

Acesta poate fi înlocuit cu iterateWhile după cum urmează:

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

{{leftbar: /@left-menu}}

Tot ce ați vrut să știți despre {iterateWhile}

Eticheta {iterateWhile} este potrivită pentru diverse trucuri în ciclurile foreach.

Să presupunem că avem următorul tabel de bază de date, în care articolele sunt împărțite în categorii:

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

Desigur, este ușor să desenezi elementele dintr-o buclă foreach sub forma unei liste:

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

Dar ce să faceți dacă doriți să redați fiecare categorie într-o listă separată? Cu alte cuvinte, cum să rezolvați sarcina de a grupa elementele dintr-o listă liniară într-un ciclu foreach. Rezultatul ar trebui să arate astfel:

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

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

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

Vă vom arăta cât de ușor și elegant poate fi rezolvată această sarcină cu iterateWhile:

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

În timp ce {foreach} marchează partea exterioară a ciclului, adică întocmirea listelor pentru fiecare categorie, etichetele {iterateWhile} indică partea interioară, adică elementele individuale. Condiția din tag-ul end spune că repetiția va continua atâta timp cât elementul curent și cel următor aparțin aceleiași categorii ($iterator->nextValue este elementul următor).

Dacă condiția este întotdeauna îndeplinită, atunci toate elementele sunt desenate în ciclul interior:

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

Rezultatul va arăta astfel:

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

La ce este bună o astfel de utilizare a iterateWhile? Prin ce diferă de soluția pe care am arătat-o la începutul acestui tutorial? Diferența constă în faptul că, dacă tabelul este gol și nu conține niciun element, nu se va afișa gol <ul></ul>.

Soluție fără {iterateWhile}

Dacă am rezolva aceeași sarcină cu sisteme de șabloane complet de bază, de exemplu în Twig, Blade sau PHP pur, soluția ar arăta cam așa:

{var $prevCatId = null}
{foreach $items as $item}
	{if $item->catId !== $prevCatId}
		{* categoria s-a schimbat *}

		{* închidem pagina anterioară <ul>, dacă nu este primul element *}
		{if $prevCatId !== null}
			</ul>
		{/if}

		{* vom deschide o nouă listă *}
		<ul>

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

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

{if $prevCatId !== null}
	{* închidem ultima listă *}
	</ul>
{/if}

Cu toate acestea, acest cod este de neînțeles și neintuitiv. Legătura dintre etichetele HTML de deschidere și închidere nu este deloc clară. Nu este clar la prima vedere dacă este vorba de o greșeală. Și este nevoie de variabile auxiliare precum $prevCatId.

În schimb, soluția cu {iterateWhile} este curată, clară, nu are nevoie de variabile auxiliare și este infailibilă.

Condiția din eticheta de închidere

Dacă specificăm o condiție în tag-ul de deschidere {iterateWhile}, comportamentul se schimbă: condiția (și avansarea la elementul următor) este executată la începutul ciclului interior, nu la sfârșitul acestuia. Astfel, în timp ce {iterateWhile} fără condiție este introdus întotdeauna, {iterateWhile $cond} este introdus doar atunci când este îndeplinită condiția $cond. În același timp, următorul element este scris în $item.

Acest lucru este util, de exemplu, în situația în care doriți să redați primul element din fiecare categorie într-un mod diferit, cum ar fi:

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

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

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

Să modificăm codul original, desenăm primul element și apoi elementele suplimentare din aceeași categorie în bucla interioară {iterateWhile}:

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

Bucle imbricate

Putem crea mai multe bucle interioare într-un ciclu și chiar le putem anina. În acest fel, de exemplu, se pot grupa subcategorii.

Să presupunem că există o altă coloană în tabelul subCatId și, pe lângă faptul că fiecare categorie se află într-o coloană separată <ul>, fiecare subcategorie va fi într-o coloană separată <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}

Filtru |batch

Gruparea elementelor liniare este, de asemenea, asigurată de un filtru batch, în loturi cu un număr fix de elemente:

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

Acesta poate fi înlocuit cu iterateWhile după cum urmează:

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