Nette Documentation Preview

syntax
Forms Rendering
***************

A formák megjelenése nagyon változatos lehet. A gyakorlatban két szélsőséggel találkozhatunk. Egyrészt szükség van arra, hogy egy alkalmazásban egy sor, egymáshoz vizuálisan hasonló űrlapot jelenítsünk meg, és értékeljük a `$form->render()` segítségével történő egyszerű, sablon nélküli megjelenítést. Ez általában az adminisztrációs felületek esetében fordul elő.

Másrészt vannak különböző űrlapok, ahol mindegyik egyedi. Megjelenésüket a legjobban a sablonban található HTML nyelv segítségével lehet leírni. És természetesen a két említett szélsőség mellett számos olyan űrlappal is találkozunk, amelyek valahol a kettő között helyezkednek el.


Renderelés Latte-val .[#toc-rendering-with-latte]
=================================================

A [Latte templating rendszer |latte:] alapvetően megkönnyíti az űrlapok és elemeik megjelenítését. Először megmutatjuk, hogyan lehet az űrlapokat manuálisan, elemenként renderelni, hogy teljes kontrollt kapjunk a kód felett. Később megmutatjuk, hogyan lehet [automatizálni |#Automatic rendering] ezt a renderelést.

A `Nette\Forms\Blueprint::latte($form)` metódus segítségével létrehozhatja a Latte sablon javaslatát az űrlaphoz, amely a böngészőoldalra kimeneti azt. Ezután csak ki kell választania a kódot egy kattintással, és be kell másolnia a projektjébe. .{data-version:3.1.15}


`{control}`
-----------

A legegyszerűbb módja egy űrlap megjelenítésének, ha egy sablonba írjuk:

```latte
{control signInForm}
```

A renderelt űrlap kinézete a [Renderer |#Renderer] és az [egyes vezérlőelemek |#HTML Attributes] konfigurálásával változtatható.


`n:name`
--------

Rendkívül egyszerű a PHP-kódban lévő űrlapdefiníciót HTML-kóddal összekapcsolni. Csak hozzá kell adni a `n:name` attribútumokat. Ennyire egyszerű!

```php
protected function createComponentSignInForm(): Form
{
	$form = new Form;
	$form->addText('username')->setRequired();
	$form->addPassword('password')->setRequired();
	$form->addSubmit('send');
	return $form;
}
```

```latte
<form n:name=signInForm class=form>
	<div>
		<label n:name=username>Username: <input n:name=username size=20 autofocus></label>
	</div>
	<div>
		<label n:name=password>Password: <input n:name=password></label>
	</div>
	<div>
		<input n:name=send class="btn btn-default">
	</div>
</form>
```

Az eredményül kapott HTML-kód kinézete teljes mértékben az Ön kezében van. Ha a `n:name` attribútumot használja a `<select>`, `<button>` vagy a `<textarea>` elemeket használ, azok belső tartalma automatikusan kitöltődik.
Ezen kívül a `<form n:name>` tag létrehoz egy helyi változót `$form` a rajzolt űrlapobjektummal és a záró `</form>` kirajzolja az összes ki nem rajzolt rejtett elemet (ugyanez vonatkozik a `{form} ... {/form}`).

Nem szabad azonban megfeledkeznünk az esetleges hibaüzenetek megjelenítéséről sem. Mindazokat, amelyeket a `addError()` módszerrel (a `{inputError}` segítségével), mind azokat, amelyeket a módszerrel adtunk hozzá az egyes elemekhez, és azokat is, amelyeket közvetlenül az űrlaphoz adtunk hozzá (a `$form->getOwnErrors()` által visszaadottak):

```latte
<form n:name=signInForm class=form>
	<ul class="errors" n:ifcontent>
		<li n:foreach="$form->getOwnErrors() as $error">{$error}</li>
	</ul>

	<div>
		<label n:name=username>Username: <input n:name=username size=20 autofocus></label>
		<span class=error n:ifcontent>{inputError username}</span>
	</div>
	<div>
		<label n:name=password>Password: <input n:name=password></label>
		<span class=error n:ifcontent>{inputError password}</span>
	</div>
	<div>
		<input n:name=send class="btn btn-default">
	</div>
</form>
```

Az összetettebb űrlapelemek, mint például a RadioList vagy CheckboxList, elemenként is megjeleníthetők:

```latte
{foreach $form[gender]->getItems() as $key => $label}
	<label n:name="gender:$key"><input n:name="gender:$key"> {$label}</label>
{/foreach}
```


`{label}` `{input}`
-------------------

Nem akarja átgondolni, hogy minden egyes elemhez milyen HTML elemet használjon a sablonban, akár `<input>`, `<textarea>` stb. A megoldás az univerzális `{input}` tag:

```latte
<form n:name=signInForm class=form>
	<ul class="errors" n:ifcontent>
		<li n:foreach="$form->getOwnErrors() as $error">{$error}</li>
	</ul>

	<div>
		{label username}Username: {input username, size: 20, autofocus: true}{/label}
		{inputError username}
	</div>
	<div>
		{label password}Password: {input password}{/label}
		{inputError password}
	</div>
	<div>
		{input send, class: "btn btn-default"}
	</div>
</form>
```

Ha az űrlap fordítót használ, a `{label}` címkékben lévő szöveg le lesz fordítva.

Az összetettebb űrlapelemek, mint például a RadioList vagy CheckboxList, elemenként is megjeleníthetők:

```latte
{foreach $form[gender]->items as $key => $label}
	{label gender:$key}{input gender:$key} {$label}{/label}
{/foreach}
```

A `<input>` magának a Checkbox elemben való megjelenítéséhez használja a `{input myCheckbox:}` címet. A HTML-attribútumokat vesszővel kell elválasztani `{input myCheckbox:, class: required}`.


`{inputError}`
--------------

Hibaüzenetet ír ki az űrlapelemhez, ha van ilyen. Az üzenet általában egy HTML-elembe van csomagolva a formázás érdekében.
Az üres elem megjelenítésének elkerülése, ha nincs üzenet, elegánsan megoldható a `n:ifcontent` segítségével:

```latte
<span class=error n:ifcontent>{inputError $input}</span>
```

A `hasErrors()` metódus segítségével észlelhetjük a hiba jelenlétét, és ennek megfelelően állíthatjuk be a szülőelem osztályát:

```latte
<div n:class="$form[username]->hasErrors() ? 'error'">
	{input username}
	{inputError username}
</div>
```


`{form}`
--------

Címkék `{form signInForm}...{/form}` alternatívája a `<form n:name="signInForm">...</form>`.


Automatikus renderelés .[#toc-automatic-rendering]
--------------------------------------------------

A `{input}` és `{label}` címkékkel könnyen létrehozhatunk egy általános sablont bármilyen űrlaphoz. Ez az összes elemét szekvenciálisan végigjárja és megjeleníti, kivéve a rejtett elemeket, amelyek automatikusan megjelenítésre kerülnek, amikor az űrlapot a `</form>` címkével zárul.
A megjelenített űrlap nevét a `$form` változóban várja el.

```latte
<form n:name=$form class=form>
	<ul class="errors" n:ifcontent>
		<li n:foreach="$form->getOwnErrors() as $error">{$error}</li>
	</ul>

	<div n:foreach="$form->getControls() as $input"
		n:if="$input->getOption(type) !== hidden">
		{label $input /}
		{input $input}
		{inputError $input}
	</div>
</form>
```

A használt önzáró párcímkék `{label .../}` a PHP kódban az űrlap definíciójából származó címkéket jelenítik meg.

Ezt az általános sablont elmentheti a `basic-form.latte` fájlba, és az űrlap megjelenítéséhez csak be kell építenie, és át kell adnia az űrlap nevét (vagy példányát) a `$form` paraméterhez:

```latte
{include basic-form.latte, form: signInForm}
```

Ha egy adott űrlap megjelenését szeretnénk befolyásolni, és egy elemet másképp rajzolni, akkor a legegyszerűbb, ha a sablonban olyan blokkokat készítünk, amelyeket később felülírhatunk.
A blokkok [dinamikus nevet |latte:template-inheritance#dynamic-block-names] is kaphatnak, így a kirajzolandó elem nevét is beillesztheti beléjük. Például:

```latte
...
	{label $input /}
	{block "input-{$input->name}"}{input $input}{/block}
...
```

A pl. `username` elemhez ez létrehozza a `input-username` blokkot, amely könnyen felülírható a [{embed} |latte:template-inheritance#unit-inheritance] tag használatával:

```latte
{embed basic-form.latte, form: signInForm}
	{block input-username}
		<span class=important>
			{include parent}
		</span>
	{/block}
{/embed}
```

Alternatívaként a `basic-form.latte` sablon teljes tartalma [definiálható |latte:template-inheritance#definitions] blokkként, beleértve a `$form` paramétert is:

```latte
{define basic-form, $form}
	<form n:name=$form class=form>
		...
	</form>
{/define}
```

Ez némileg megkönnyíti a használatát:

```latte
{embed basic-form, signInForm}
	...
{/embed}
```

A blokkot csak egy helyre kell importálnia, az elrendezési sablon elejére:

```latte
{import basic-form.latte}
```


Speciális esetek .[#toc-special-cases]
--------------------------------------

Ha csak az űrlap belső részét kell megjelenítenie HTML címkék nélkül `<form>`, például a snippetek elküldésekor, rejtse el őket a `n:tag-if` attribútummal:

```latte
<form n:name=signInForm n:tag-if=false>
	<div>
		<label n:name=username>Username: <input n:name=username></label>
		{inputError username}
	</div>
</form>
```

A `formContainer` címke az űrlapkonténeren belüli bemenetek megjelenítését segíti.

```latte
<p>Which news you wish to receive:</p>

{formContainer emailNews}
<ul>
	<li>{input sport} {label sport /}</li>
	<li>{input science} {label science /}</li>
</ul>
{/formContainer}
```


Renderelés Latte nélkül .[#toc-rendering-without-latte]
=======================================================

A legegyszerűbb módja egy űrlap megjelenítésének a következő hívás:

```php
$form->render();
```

A renderelt űrlap kinézete a [Renderer |#Renderer] és az [egyes vezérlőelemek |#HTML Attributes] konfigurálásával változtatható.


Kézi renderelés .[#toc-manual-rendering]
----------------------------------------

Minden űrlapelem rendelkezik olyan metódusokkal, amelyek az űrlapmező és a címke HTML-kódját generálják. A metódusok vagy egy karakterlánc vagy egy [Nette\Utils\Html |utils:html-elements] objektum formájában adhatják vissza:

- `getControl(): Html|string` az elem HTML kódját adja vissza
- A `getLabel($caption = null): Html|string|null` a címke HTML-kódját adja vissza, ha van ilyen.

Ez lehetővé teszi az űrlap elemenkénti megjelenítését:

```php
<?php $form->render('begin') ?>
<?php $form->render('errors') ?>

<div>
	<?= $form['name']->getLabel() ?>
	<?= $form['name']->getControl() ?>
	<span class=error><?= htmlspecialchars($form['name']->getError()) ?></span>
</div>

<div>
	<?= $form['age']->getLabel() ?>
	<?= $form['age']->getControl() ?>
	<span class=error><?= htmlspecialchars($form['age']->getError()) ?></span>
</div>

// ...

<?php $form->render('end') ?>
```

Míg néhány elem esetében a `getControl()` egyetlen HTML-elemet ad vissza (pl. `<input>`, `<select>` stb.), mások esetében egy egész HTML-kódot ad vissza (CheckboxList, RadioList).
Ebben az esetben használhat olyan metódusokat, amelyek külön-külön generálnak beviteli és címkézési adatokat, minden egyes elemhez külön-külön:

- `getControlPart($key = null): ?Html` egy elem HTML-kódját adja vissza.
- `getLabelPart($key = null): ?Html` visszaadja egy elem címkéjének HTML-kódját.

.[note]
Ezek a metódusok történelmi okokból a `get` előtaggal vannak ellátva, de a `generate` jobb lenne, mivel minden egyes híváskor egy új `Html` elemet hoz létre és ad vissza.


Renderer .[#toc-renderer]
=========================

Ez egy objektum, amely az űrlap renderelését biztosítja. A `$form->setRenderer` metódussal lehet beállítani. A `$form->render()` metódus meghívásakor adják át a vezérlést.

Ha nem állítunk be egyéni renderelőt, akkor az alapértelmezett renderelőt [api:Nette\Forms\Rendering\DefaultFormRenderer] fogja használni. Ez az űrlap elemeit HTML táblázatként rendereli. A kimenet így néz ki:

```latte
<table>
<tr class="required">
	<th><label class="required" for="frm-name">Name:</label></th>

	<td><input type="text" class="text" name="name" id="frm-name" required value=""></td>
</tr>

<tr class="required">
	<th><label class="required" for="frm-age">Age:</label></th>

	<td><input type="text" class="text" name="age" id="frm-age" required value=""></td>
</tr>

<tr>
	<th><label>Gender:</label></th>
	...
```

Sok webdesigner más jelöléseket, például listát preferál. Beállíthatjuk a `DefaultFormRenderer` címet úgy, hogy egyáltalán ne rendereljük táblázatba. Csak megfelelő [$wrappereket |api:Nette\Forms\Rendering\DefaultFormRenderer::$wrappers] kell beállítanunk. Az első index mindig egy területet, a második pedig egy elemet jelöl. A képen az összes megfelelő terület látható:

[* form-areas-en.webp *]

Alapértelmezés szerint a `controls` egy csoportja be van csomagolva egy `<table>`, és minden egyes `pair` egy táblázat sora `<tr>` amely a `label` és a `control` egy párját tartalmazza (cellák `<th>` és `<td>`). Változtassuk meg ezeket a burkolóelemeket. A `controls` -t be fogjuk csomagolni `<dl>`, a `pair` -t önmagában hagyjuk, a `label` -t a következőbe tesszük `<dt>` és a `control` -t a következőbe csomagoljuk `<dd>`:

```php
$renderer = $form->getRenderer();
$renderer->wrappers['controls']['container'] = 'dl';
$renderer->wrappers['pair']['container'] = null;
$renderer->wrappers['label']['container'] = 'dt';
$renderer->wrappers['control']['container'] = 'dd';

$form->render();
```

Az eredmény a következő részlet:

```latte
<dl>
	<dt><label class="required" for="frm-name">Name:</label></dt>

	<dd><input type="text" class="text" name="name" id="frm-name" required value=""></dd>


	<dt><label class="required" for="frm-age">Age:</label></dt>

	<dd><input type="text" class="text" name="age" id="frm-age" required value=""></dd>


	<dt><label>Gender:</label></dt>
	...
</dl>
```

A burkolók számos attribútumot befolyásolhatnak. Például:

- speciális CSS osztályok hozzáadása minden egyes űrlapbemenethez
- megkülönböztetni a páratlan és páros sorokat
- a kötelező és opcionális elemek eltérő rajzolása
- állítsa be, hogy a hibaüzenetek az űrlap felett vagy az egyes elemek közelében jelenjenek meg.


Opciók .[#toc-options]
----------------------

A Renderer viselkedése az egyes űrlapelemek *opciók* beállításával is szabályozható. Így beállítható a beviteli mező mellett megjelenő tooltip:

```php
$form->addText('phone', 'Number:')
	->setOption('description', 'This number will remain hidden');
```

Ha HTML tartalmat szeretnénk elhelyezni benne, akkor a [Html |utils:html-elements] osztályt használjuk.

```php
use Nette\Utils\Html;

$form->addText('phone', 'Phone:')
	->setOption('description', Html::el('p')
		->setHtml('<a href="...">Terms of service.</a>')
	);
```

.[tip]
Html elem is használható a címke helyett: `$form->addCheckbox('conditions', $label)`.


Bemenetek csoportosítása .[#toc-grouping-inputs]
------------------------------------------------

A renderelő lehetővé teszi az elemek vizuális csoportokba (mezőcsoportokba) való csoportosítását:

```php
$form->addGroup('Personal data');
```

Új csoport létrehozása aktiválja azt - minden további hozzáadott elemet hozzáad ehhez a csoporthoz. Egy űrlapot így építhetünk fel:

```php
$form = new Form;
$form->addGroup('Personal data');
$form->addText('name', 'Your name:');
$form->addInteger('age', 'Your age:');
$form->addEmail('email', 'Email:');

$form->addGroup('Shipping address');
$form->addCheckbox('send', 'Ship to address');
$form->addText('street', 'Street:');
$form->addText('city', 'City:');
$form->addSelect('country', 'Country:', $countries);
```

A renderelő először a csoportokat rajzolja ki, majd azokat az elemeket, amelyek nem tartoznak egyik csoporthoz sem.


Bootstrap támogatás .[#toc-bootstrap-support]
---------------------------------------------

[Példákat |https://github.com/nette/forms/tree/master/examples] talál a [Twitter Bootstrap 2 |https://github.com/nette/forms/blob/a0bc775b96b30780270bdec06396ca985168f11a/examples/bootstrap2-rendering.php#L58], [Bootstrap 3 |https://github.com/nette/forms/blob/a0bc775b96b30780270bdec06396ca985168f11a/examples/bootstrap3-rendering.php#L58] és [Bootstrap 4 |https://github.com/nette/forms/blob/96b3e90/examples/bootstrap4-rendering.php] Renderer konfigurációjára.


HTML attribútumok .[#toc-html-attributes]
=========================================

A `setHtmlAttribute(string $name, $value = true)` segítségével bármilyen HTML-attribútumot beállíthat az űrlapvezérlőkhöz:

```php
$form->addInteger('number', 'Szám:')
	->setHtmlAttribute('class', 'big-number');

$form->addSelect('rank', 'Order by:', ['price', 'name'])
	->setHtmlAttribute('onchange', 'submit()'); // változáskor meghívja a submit() JS függvényt.


// <form>-ra való alkalmazás
$form->setHtmlAttribute('id', 'myForm');
```

Input type beállítása:

```php
$form->addText('tel', 'Your telephone:')
	->setHtmlType('tel')
	->setHtmlAttribute('placeholder', 'Please, fill in your telephone');
```

HTML attribútumot állíthatunk be a rádió- vagy jelölőnégyzet-listák egyes elemeihez, mindegyikhez különböző értékekkel.
Figyeljük meg a kettőspontot a `style:` után, hogy az értéket a kulcs szerint válasszuk ki:

```php
$colors = ['r' => 'red', 'g' => 'green', 'b' => 'blue'];
$styles = ['r' => 'background:red', 'g' => 'background:green'];
$form->addCheckboxList('colors', 'Colors:', $colors)
	->setHtmlAttribute('style:', $styles);
```

Renders:

```latte
<label><input type="checkbox" name="colors[]" style="background:red" value="r">red</label>
<label><input type="checkbox" name="colors[]" style="background:green" value="g">green</label>
<label><input type="checkbox" name="colors[]" value="b">blue</label>
```

A logikai HTML-attribútumok (amelyeknek nincs értéke, mint például a `readonly`) esetében kérdőjelet használhat:

```php
$colors = ['r' => 'red', 'g' => 'green', 'b' => 'blue'];
$form->addCheckboxList('colors', 'Colors:', $colors)
	->setHtmlAttribute('readonly?', 'r'); // több kulcs esetén használjunk tömböt, pl. ['r', 'g']
```

Renders:

```latte
<label><input type="checkbox" name="colors[]" readonly value="r">red</label>
<label><input type="checkbox" name="colors[]" value="g">green</label>
<label><input type="checkbox" name="colors[]" value="b">blue</label>
```

A selectboxok esetében a `setHtmlAttribute()` módszer beállítja az attribútumokat a `<select>` elemhez. Ha az attribútumokat minden egyes
`<option>`, a `setOptionAttribute()` módszert fogjuk használni. A fent használt kettőspont és kérdőjel is működik:

```php
$form->addSelect('colors', 'Colors:', $colors)
	->setOptionAttribute('style:', $styles);
```

Renders:

```latte
<select name="colors">
	<option value="r" style="background:red">red</option>
	<option value="g" style="background:green">green</option>
	<option value="b">blue</option>
</select>
```


Prototípusok .[#toc-prototypes]
-------------------------------

A HTML-attribútumok beállításának alternatív módja a sablon módosítása, amelyből a HTML-elem generálódik. A sablon egy `Html` objektum, és a `getControlPrototype()` metódus adja vissza:

```php
$input = $form->addInteger('number');
$html = $input->getControlPrototype(); // <input>
$html->class('big-number'); // <input class="big-number">
```

A `getLabelPrototype()` által visszaadott címke sablon is módosítható ilyen módon:

```php
$html = $input->getLabelPrototype(); // <label>
$html->class('distinctive'); // <label class="distinctive">
```

A Checkbox, CheckboxList és RadioList elemek esetében befolyásolhatja az elemet körülvevő elemsablont. Ezt a `getContainerPrototype()` adja vissza. Alapértelmezés szerint ez egy "üres" elem, tehát semmi sem kerül megjelenítésre, de ha nevet adunk neki, akkor megjelenítésre kerül:

```php
$input = $form->addCheckbox('send');
echo $input->getControl();
// <label><input type="checkbox" name="send"></label>

$html = $input->getContainerPrototype();
$html->setName('div'); // <div>
$html->class('check'); // <div class="check">
echo $input->getControl();
// <div class="check"><label><input type="checkbox" name="send"></label></div>
```

A CheckboxList és RadioList esetében a `getSeparatorPrototype()` metódus által visszaadott elemelválasztó mintát is lehet befolyásolni. Alapértelmezés szerint ez egy elem `<br>`. Ha ezt páros elemre változtatjuk, akkor az egyes elemeket elválasztás helyett be fogja burkolni.
Lehetőség van az elemcímkék HTML elemsablonjának befolyásolására is, amely a `getItemLabelPrototype()` metódust adja vissza.


Fordítás .[#toc-translating]
============================

Ha többnyelvű alkalmazást programoz, valószínűleg különböző nyelveken kell megjelenítenie az űrlapot. A Nette Framework erre a célra egy fordítási felületet definiál [api:Nette\Localization\Translator]. A Nette-ben nincs alapértelmezett implementáció, igényei szerint választhat több kész megoldás közül, amelyeket a [Componette-en |https://componette.org/search/localization] talál. A dokumentációjukból megtudhatja, hogyan kell a fordítót konfigurálni.

Az űrlap támogatja a szövegek kiadását a fordítóprogramon keresztül. Ezt a `setTranslator()` metódus segítségével adjuk át:

```php
$form->setTranslator($translator);
```

Mostantól kezdve nemcsak az összes címke, hanem az összes hibaüzenet vagy a kiválasztó dobozok bejegyzései is le lesznek fordítva egy másik nyelvre.

Lehetőség van az egyes űrlapelemekhez más fordítót beállítani, vagy a fordítást teljesen kikapcsolni a `null` címmel:

```php
$form->addSelect('carModel', 'Model:', $cars)
	->setTranslator(null);
```

Az [érvényesítési szabályok |validation] esetében a fordítónak specifikus paramétereket is át kell adni, például a szabály esetében:

```php
$form->addPassword('password', 'Password:')
	->addRule($form::MinLength, 'Password has to be at least %d characters long', 8)
```

A fordítót a következő paraméterekkel hívjuk meg:

```php
$translator->translate('Password has to be at least %d characters long', 8);
```

így a `characters` szóhoz a megfelelő többes számot tudja kiválasztani.


Esemény onRender .[#toc-event-onrender]
=======================================

Közvetlenül az űrlap renderelése előtt meghívhatjuk a kódunkat. Ez például HTML-osztályokat adhat az űrlap elemeihez a megfelelő megjelenítés érdekében. A kódot a `onRender` tömbhöz adjuk hozzá:

```php
$form->onRender[] = function ($form) {
	BootstrapCSS::initialize($form);
};
```

Forms Rendering

A formák megjelenése nagyon változatos lehet. A gyakorlatban két szélsőséggel találkozhatunk. Egyrészt szükség van arra, hogy egy alkalmazásban egy sor, egymáshoz vizuálisan hasonló űrlapot jelenítsünk meg, és értékeljük a $form->render() segítségével történő egyszerű, sablon nélküli megjelenítést. Ez általában az adminisztrációs felületek esetében fordul elő.

Másrészt vannak különböző űrlapok, ahol mindegyik egyedi. Megjelenésüket a legjobban a sablonban található HTML nyelv segítségével lehet leírni. És természetesen a két említett szélsőség mellett számos olyan űrlappal is találkozunk, amelyek valahol a kettő között helyezkednek el.

Renderelés Latte-val

Latte templating rendszer alapvetően megkönnyíti az űrlapok és elemeik megjelenítését. Először megmutatjuk, hogyan lehet az űrlapokat manuálisan, elemenként renderelni, hogy teljes kontrollt kapjunk a kód felett. Később megmutatjuk, hogyan lehet automatizálni ezt a renderelést.

A Nette\Forms\Blueprint::latte($form) metódus segítségével létrehozhatja a Latte sablon javaslatát az űrlaphoz, amely a böngészőoldalra kimeneti azt. Ezután csak ki kell választania a kódot egy kattintással, és be kell másolnia a projektjébe.

{control}

A legegyszerűbb módja egy űrlap megjelenítésének, ha egy sablonba írjuk:

{control signInForm}

A renderelt űrlap kinézete a Renderer és az egyes vezérlőelemek konfigurálásával változtatható.

n:name

Rendkívül egyszerű a PHP-kódban lévő űrlapdefiníciót HTML-kóddal összekapcsolni. Csak hozzá kell adni a n:name attribútumokat. Ennyire egyszerű!

protected function createComponentSignInForm(): Form
{
	$form = new Form;
	$form->addText('username')->setRequired();
	$form->addPassword('password')->setRequired();
	$form->addSubmit('send');
	return $form;
}
<form n:name=signInForm class=form>
	<div>
		<label n:name=username>Username: <input n:name=username size=20 autofocus></label>
	</div>
	<div>
		<label n:name=password>Password: <input n:name=password></label>
	</div>
	<div>
		<input n:name=send class="btn btn-default">
	</div>
</form>

Az eredményül kapott HTML-kód kinézete teljes mértékben az Ön kezében van. Ha a n:name attribútumot használja a <select>, <button> vagy a <textarea> elemeket használ, azok belső tartalma automatikusan kitöltődik. Ezen kívül a <form n:name> tag létrehoz egy helyi változót $form a rajzolt űrlapobjektummal és a záró </form> kirajzolja az összes ki nem rajzolt rejtett elemet (ugyanez vonatkozik a {form} ... {/form}).

Nem szabad azonban megfeledkeznünk az esetleges hibaüzenetek megjelenítéséről sem. Mindazokat, amelyeket a addError() módszerrel (a {inputError} segítségével), mind azokat, amelyeket a módszerrel adtunk hozzá az egyes elemekhez, és azokat is, amelyeket közvetlenül az űrlaphoz adtunk hozzá (a $form->getOwnErrors() által visszaadottak):

<form n:name=signInForm class=form>
	<ul class="errors" n:ifcontent>
		<li n:foreach="$form->getOwnErrors() as $error">{$error}</li>
	</ul>

	<div>
		<label n:name=username>Username: <input n:name=username size=20 autofocus></label>
		<span class=error n:ifcontent>{inputError username}</span>
	</div>
	<div>
		<label n:name=password>Password: <input n:name=password></label>
		<span class=error n:ifcontent>{inputError password}</span>
	</div>
	<div>
		<input n:name=send class="btn btn-default">
	</div>
</form>

Az összetettebb űrlapelemek, mint például a RadioList vagy CheckboxList, elemenként is megjeleníthetők:

{foreach $form[gender]->getItems() as $key => $label}
	<label n:name="gender:$key"><input n:name="gender:$key"> {$label}</label>
{/foreach}

{label} {input}

Nem akarja átgondolni, hogy minden egyes elemhez milyen HTML elemet használjon a sablonban, akár <input>, <textarea> stb. A megoldás az univerzális {input} tag:

<form n:name=signInForm class=form>
	<ul class="errors" n:ifcontent>
		<li n:foreach="$form->getOwnErrors() as $error">{$error}</li>
	</ul>

	<div>
		{label username}Username: {input username, size: 20, autofocus: true}{/label}
		{inputError username}
	</div>
	<div>
		{label password}Password: {input password}{/label}
		{inputError password}
	</div>
	<div>
		{input send, class: "btn btn-default"}
	</div>
</form>

Ha az űrlap fordítót használ, a {label} címkékben lévő szöveg le lesz fordítva.

Az összetettebb űrlapelemek, mint például a RadioList vagy CheckboxList, elemenként is megjeleníthetők:

{foreach $form[gender]->items as $key => $label}
	{label gender:$key}{input gender:$key} {$label}{/label}
{/foreach}

A <input> magának a Checkbox elemben való megjelenítéséhez használja a {input myCheckbox:} címet. A HTML-attribútumokat vesszővel kell elválasztani {input myCheckbox:, class: required}.

{inputError}

Hibaüzenetet ír ki az űrlapelemhez, ha van ilyen. Az üzenet általában egy HTML-elembe van csomagolva a formázás érdekében. Az üres elem megjelenítésének elkerülése, ha nincs üzenet, elegánsan megoldható a n:ifcontent segítségével:

<span class=error n:ifcontent>{inputError $input}</span>

A hasErrors() metódus segítségével észlelhetjük a hiba jelenlétét, és ennek megfelelően állíthatjuk be a szülőelem osztályát:

<div n:class="$form[username]->hasErrors() ? 'error'">
	{input username}
	{inputError username}
</div>

{form}

Címkék {form signInForm}...{/form} alternatívája a <form n:name="signInForm">...</form>.

Automatikus renderelés

A {input} és {label} címkékkel könnyen létrehozhatunk egy általános sablont bármilyen űrlaphoz. Ez az összes elemét szekvenciálisan végigjárja és megjeleníti, kivéve a rejtett elemeket, amelyek automatikusan megjelenítésre kerülnek, amikor az űrlapot a </form> címkével zárul. A megjelenített űrlap nevét a $form változóban várja el.

<form n:name=$form class=form>
	<ul class="errors" n:ifcontent>
		<li n:foreach="$form->getOwnErrors() as $error">{$error}</li>
	</ul>

	<div n:foreach="$form->getControls() as $input"
		n:if="$input->getOption(type) !== hidden">
		{label $input /}
		{input $input}
		{inputError $input}
	</div>
</form>

A használt önzáró párcímkék {label .../} a PHP kódban az űrlap definíciójából származó címkéket jelenítik meg.

Ezt az általános sablont elmentheti a basic-form.latte fájlba, és az űrlap megjelenítéséhez csak be kell építenie, és át kell adnia az űrlap nevét (vagy példányát) a $form paraméterhez:

{include basic-form.latte, form: signInForm}

Ha egy adott űrlap megjelenését szeretnénk befolyásolni, és egy elemet másképp rajzolni, akkor a legegyszerűbb, ha a sablonban olyan blokkokat készítünk, amelyeket később felülírhatunk. A blokkok dinamikus nevet is kaphatnak, így a kirajzolandó elem nevét is beillesztheti beléjük. Például:

...
	{label $input /}
	{block "input-{$input->name}"}{input $input}{/block}
...

A pl. username elemhez ez létrehozza a input-username blokkot, amely könnyen felülírható a {embed} tag használatával:

{embed basic-form.latte, form: signInForm}
	{block input-username}
		<span class=important>
			{include parent}
		</span>
	{/block}
{/embed}

Alternatívaként a basic-form.latte sablon teljes tartalma definiálható blokkként, beleértve a $form paramétert is:

{define basic-form, $form}
	<form n:name=$form class=form>
		...
	</form>
{/define}

Ez némileg megkönnyíti a használatát:

{embed basic-form, signInForm}
	...
{/embed}

A blokkot csak egy helyre kell importálnia, az elrendezési sablon elejére:

{import basic-form.latte}

Speciális esetek

Ha csak az űrlap belső részét kell megjelenítenie HTML címkék nélkül <form>, például a snippetek elküldésekor, rejtse el őket a n:tag-if attribútummal:

<form n:name=signInForm n:tag-if=false>
	<div>
		<label n:name=username>Username: <input n:name=username></label>
		{inputError username}
	</div>
</form>

A formContainer címke az űrlapkonténeren belüli bemenetek megjelenítését segíti.

<p>Which news you wish to receive:</p>

{formContainer emailNews}
<ul>
	<li>{input sport} {label sport /}</li>
	<li>{input science} {label science /}</li>
</ul>
{/formContainer}

Renderelés Latte nélkül

A legegyszerűbb módja egy űrlap megjelenítésének a következő hívás:

$form->render();

A renderelt űrlap kinézete a Renderer és az egyes vezérlőelemek konfigurálásával változtatható.

Kézi renderelés

Minden űrlapelem rendelkezik olyan metódusokkal, amelyek az űrlapmező és a címke HTML-kódját generálják. A metódusok vagy egy karakterlánc vagy egy Nette\Utils\Html objektum formájában adhatják vissza:

  • getControl(): Html|string az elem HTML kódját adja vissza
  • A getLabel($caption = null): Html|string|null a címke HTML-kódját adja vissza, ha van ilyen.

Ez lehetővé teszi az űrlap elemenkénti megjelenítését:

<?php $form->render('begin') ?>
<?php $form->render('errors') ?>

<div>
	<?= $form['name']->getLabel() ?>
	<?= $form['name']->getControl() ?>
	<span class=error><?= htmlspecialchars($form['name']->getError()) ?></span>
</div>

<div>
	<?= $form['age']->getLabel() ?>
	<?= $form['age']->getControl() ?>
	<span class=error><?= htmlspecialchars($form['age']->getError()) ?></span>
</div>

// ...

<?php $form->render('end') ?>

Míg néhány elem esetében a getControl() egyetlen HTML-elemet ad vissza (pl. <input>, <select> stb.), mások esetében egy egész HTML-kódot ad vissza (CheckboxList, RadioList). Ebben az esetben használhat olyan metódusokat, amelyek külön-külön generálnak beviteli és címkézési adatokat, minden egyes elemhez külön-külön:

  • getControlPart($key = null): ?Html egy elem HTML-kódját adja vissza.
  • getLabelPart($key = null): ?Html visszaadja egy elem címkéjének HTML-kódját.

Ezek a metódusok történelmi okokból a get előtaggal vannak ellátva, de a generate jobb lenne, mivel minden egyes híváskor egy új Html elemet hoz létre és ad vissza.

Renderer

Ez egy objektum, amely az űrlap renderelését biztosítja. A $form->setRenderer metódussal lehet beállítani. A $form->render() metódus meghívásakor adják át a vezérlést.

Ha nem állítunk be egyéni renderelőt, akkor az alapértelmezett renderelőt Nette\Forms\Rendering\DefaultFormRenderer fogja használni. Ez az űrlap elemeit HTML táblázatként rendereli. A kimenet így néz ki:

<table>
<tr class="required">
	<th><label class="required" for="frm-name">Name:</label></th>

	<td><input type="text" class="text" name="name" id="frm-name" required value=""></td>
</tr>

<tr class="required">
	<th><label class="required" for="frm-age">Age:</label></th>

	<td><input type="text" class="text" name="age" id="frm-age" required value=""></td>
</tr>

<tr>
	<th><label>Gender:</label></th>
	...

Sok webdesigner más jelöléseket, például listát preferál. Beállíthatjuk a DefaultFormRenderer címet úgy, hogy egyáltalán ne rendereljük táblázatba. Csak megfelelő $wrappereket kell beállítanunk. Az első index mindig egy területet, a második pedig egy elemet jelöl. A képen az összes megfelelő terület látható:

Alapértelmezés szerint a controls egy csoportja be van csomagolva egy <table>, és minden egyes pair egy táblázat sora <tr> amely a label és a control egy párját tartalmazza (cellák <th> és <td>). Változtassuk meg ezeket a burkolóelemeket. A controls -t be fogjuk csomagolni <dl>, a pair -t önmagában hagyjuk, a label -t a következőbe tesszük <dt> és a control -t a következőbe csomagoljuk <dd>:

$renderer = $form->getRenderer();
$renderer->wrappers['controls']['container'] = 'dl';
$renderer->wrappers['pair']['container'] = null;
$renderer->wrappers['label']['container'] = 'dt';
$renderer->wrappers['control']['container'] = 'dd';

$form->render();

Az eredmény a következő részlet:

<dl>
	<dt><label class="required" for="frm-name">Name:</label></dt>

	<dd><input type="text" class="text" name="name" id="frm-name" required value=""></dd>


	<dt><label class="required" for="frm-age">Age:</label></dt>

	<dd><input type="text" class="text" name="age" id="frm-age" required value=""></dd>


	<dt><label>Gender:</label></dt>
	...
</dl>

A burkolók számos attribútumot befolyásolhatnak. Például:

  • speciális CSS osztályok hozzáadása minden egyes űrlapbemenethez
  • megkülönböztetni a páratlan és páros sorokat
  • a kötelező és opcionális elemek eltérő rajzolása
  • állítsa be, hogy a hibaüzenetek az űrlap felett vagy az egyes elemek közelében jelenjenek meg.

Opciók

A Renderer viselkedése az egyes űrlapelemek opciók beállításával is szabályozható. Így beállítható a beviteli mező mellett megjelenő tooltip:

$form->addText('phone', 'Number:')
	->setOption('description', 'This number will remain hidden');

Ha HTML tartalmat szeretnénk elhelyezni benne, akkor a Html osztályt használjuk.

use Nette\Utils\Html;

$form->addText('phone', 'Phone:')
	->setOption('description', Html::el('p')
		->setHtml('<a href="...">Terms of service.</a>')
	);

Html elem is használható a címke helyett: $form->addCheckbox('conditions', $label).

Bemenetek csoportosítása

A renderelő lehetővé teszi az elemek vizuális csoportokba (mezőcsoportokba) való csoportosítását:

$form->addGroup('Personal data');

Új csoport létrehozása aktiválja azt – minden további hozzáadott elemet hozzáad ehhez a csoporthoz. Egy űrlapot így építhetünk fel:

$form = new Form;
$form->addGroup('Personal data');
$form->addText('name', 'Your name:');
$form->addInteger('age', 'Your age:');
$form->addEmail('email', 'Email:');

$form->addGroup('Shipping address');
$form->addCheckbox('send', 'Ship to address');
$form->addText('street', 'Street:');
$form->addText('city', 'City:');
$form->addSelect('country', 'Country:', $countries);

A renderelő először a csoportokat rajzolja ki, majd azokat az elemeket, amelyek nem tartoznak egyik csoporthoz sem.

Bootstrap támogatás

Példákat talál a Twitter Bootstrap 2, Bootstrap 3 és Bootstrap 4 Renderer konfigurációjára.

HTML attribútumok

A setHtmlAttribute(string $name, $value = true) segítségével bármilyen HTML-attribútumot beállíthat az űrlapvezérlőkhöz:

$form->addInteger('number', 'Szám:')
	->setHtmlAttribute('class', 'big-number');

$form->addSelect('rank', 'Order by:', ['price', 'name'])
	->setHtmlAttribute('onchange', 'submit()'); // változáskor meghívja a submit() JS függvényt.


// <form>-ra való alkalmazás
$form->setHtmlAttribute('id', 'myForm');

Input type beállítása:

$form->addText('tel', 'Your telephone:')
	->setHtmlType('tel')
	->setHtmlAttribute('placeholder', 'Please, fill in your telephone');

HTML attribútumot állíthatunk be a rádió- vagy jelölőnégyzet-listák egyes elemeihez, mindegyikhez különböző értékekkel. Figyeljük meg a kettőspontot a style: után, hogy az értéket a kulcs szerint válasszuk ki:

$colors = ['r' => 'red', 'g' => 'green', 'b' => 'blue'];
$styles = ['r' => 'background:red', 'g' => 'background:green'];
$form->addCheckboxList('colors', 'Colors:', $colors)
	->setHtmlAttribute('style:', $styles);

Renders:

<label><input type="checkbox" name="colors[]" style="background:red" value="r">red</label>
<label><input type="checkbox" name="colors[]" style="background:green" value="g">green</label>
<label><input type="checkbox" name="colors[]" value="b">blue</label>

A logikai HTML-attribútumok (amelyeknek nincs értéke, mint például a readonly) esetében kérdőjelet használhat:

$colors = ['r' => 'red', 'g' => 'green', 'b' => 'blue'];
$form->addCheckboxList('colors', 'Colors:', $colors)
	->setHtmlAttribute('readonly?', 'r'); // több kulcs esetén használjunk tömböt, pl. ['r', 'g']

Renders:

<label><input type="checkbox" name="colors[]" readonly value="r">red</label>
<label><input type="checkbox" name="colors[]" value="g">green</label>
<label><input type="checkbox" name="colors[]" value="b">blue</label>

A selectboxok esetében a setHtmlAttribute() módszer beállítja az attribútumokat a <select> elemhez. Ha az attribútumokat minden egyes <option>, a setOptionAttribute() módszert fogjuk használni. A fent használt kettőspont és kérdőjel is működik:

$form->addSelect('colors', 'Colors:', $colors)
	->setOptionAttribute('style:', $styles);

Renders:

<select name="colors">
	<option value="r" style="background:red">red</option>
	<option value="g" style="background:green">green</option>
	<option value="b">blue</option>
</select>

Prototípusok

A HTML-attribútumok beállításának alternatív módja a sablon módosítása, amelyből a HTML-elem generálódik. A sablon egy Html objektum, és a getControlPrototype() metódus adja vissza:

$input = $form->addInteger('number');
$html = $input->getControlPrototype(); // <input>
$html->class('big-number'); // <input class="big-number">

A getLabelPrototype() által visszaadott címke sablon is módosítható ilyen módon:

$html = $input->getLabelPrototype(); // <label>
$html->class('distinctive'); // <label class="distinctive">

A Checkbox, CheckboxList és RadioList elemek esetében befolyásolhatja az elemet körülvevő elemsablont. Ezt a getContainerPrototype() adja vissza. Alapértelmezés szerint ez egy „üres“ elem, tehát semmi sem kerül megjelenítésre, de ha nevet adunk neki, akkor megjelenítésre kerül:

$input = $form->addCheckbox('send');
echo $input->getControl();
// <label><input type="checkbox" name="send"></label>

$html = $input->getContainerPrototype();
$html->setName('div'); // <div>
$html->class('check'); // <div class="check">
echo $input->getControl();
// <div class="check"><label><input type="checkbox" name="send"></label></div>

A CheckboxList és RadioList esetében a getSeparatorPrototype() metódus által visszaadott elemelválasztó mintát is lehet befolyásolni. Alapértelmezés szerint ez egy elem <br>. Ha ezt páros elemre változtatjuk, akkor az egyes elemeket elválasztás helyett be fogja burkolni. Lehetőség van az elemcímkék HTML elemsablonjának befolyásolására is, amely a getItemLabelPrototype() metódust adja vissza.

Fordítás

Ha többnyelvű alkalmazást programoz, valószínűleg különböző nyelveken kell megjelenítenie az űrlapot. A Nette Framework erre a célra egy fordítási felületet definiál Nette\Localization\Translator. A Nette-ben nincs alapértelmezett implementáció, igényei szerint választhat több kész megoldás közül, amelyeket a Componette-en talál. A dokumentációjukból megtudhatja, hogyan kell a fordítót konfigurálni.

Az űrlap támogatja a szövegek kiadását a fordítóprogramon keresztül. Ezt a setTranslator() metódus segítségével adjuk át:

$form->setTranslator($translator);

Mostantól kezdve nemcsak az összes címke, hanem az összes hibaüzenet vagy a kiválasztó dobozok bejegyzései is le lesznek fordítva egy másik nyelvre.

Lehetőség van az egyes űrlapelemekhez más fordítót beállítani, vagy a fordítást teljesen kikapcsolni a null címmel:

$form->addSelect('carModel', 'Model:', $cars)
	->setTranslator(null);

Az érvényesítési szabályok esetében a fordítónak specifikus paramétereket is át kell adni, például a szabály esetében:

$form->addPassword('password', 'Password:')
	->addRule($form::MinLength, 'Password has to be at least %d characters long', 8)

A fordítót a következő paraméterekkel hívjuk meg:

$translator->translate('Password has to be at least %d characters long', 8);

így a characters szóhoz a megfelelő többes számot tudja kiválasztani.

Esemény onRender

Közvetlenül az űrlap renderelése előtt meghívhatjuk a kódunkat. Ez például HTML-osztályokat adhat az űrlap elemeihez a megfelelő megjelenítés érdekében. A kódot a onRender tömbhöz adjuk hozzá:

$form->onRender[] = function ($form) {
	BootstrapCSS::initialize($form);
};