Forms Rendering
Az űrlapok megjelenése nagymértékben eltérhet egymástól. Valójában két szélsőség létezik. Az egyik oldal az, amikor egy sor nagyon hasonló űrlapot kell újra és újra megjeleníteni, kevés vagy semmi erőfeszítéssel. Általában adminisztrációk és back-endek.
A másik oldal az apró, édes formák, amelyek mindegyike egy-egy műalkotás. Ezek elrendezése a legjobban HTML-ben írható meg. Természetesen ezeken a végleteken kívül is sok űrlap létezik a kettő között.
Latte
A 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.
{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}
Kódjavaslat {formPrint}
Hasonló Latte kódot generálhat egy űrlaphoz a {formPrint}
tag használatával. Ha ezt egy sablonba helyezi, a
normál megjelenítés helyett a kódtervezetet fogja látni. Ezután csak válassza ki, és másolja be a projektjébe.
{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>
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 egy űrlap belső tartalmát kell megjelenítenie anélkül, hogy a <form>
&
</form>
HTML-címkéket, például egy AJAX-kérés során, akkor a
{formContext} … {/formContext}
segítségével nyithatja meg és zárhatja be az űrlapot. Logikai értelemben
hasonlóan működik, mint a {form}
, itt lehetővé teszi, hogy más címkéket használjon az űrlapelemek
megrajzolásához, ugyanakkor nem rajzol semmit.
{formContext signForm}
<div>
<label n:name=username>Username: <input n:name=username></label>
{inputError username}
</div>
{/formContext}
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}
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" 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" 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" value=""></dd>
<dt><label class="required" for="frm-age">Age:</label></dt>
<dd><input type="text" class="text" name="age" id="frm-age" 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);
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);
};