Űrlapok megjelenítése
Az űrlapok megjelenése nagyon változatos lehet. A gyakorlatban két szélsőséggel találkozhatunk. Az egyik oldalon az az
igény áll, hogy az alkalmazásban számos olyan űrlapot jelenítsünk meg, amelyek vizuálisan hasonlítanak egymásra, mint
két tojás, és értékelnénk az egyszerű megjelenítést sablon nélkül a $form->render()
segítségével. Ez
általában az adminisztrációs felületek esete.
A másik oldalon pedig ott vannak a változatos űrlapok, amelyekre igaz: minden darab egyedi. Formájukat leginkább HTML nyelven írhatjuk le az űrlap sablonjában. És természetesen a két említett szélsőségen kívül számos olyan űrlappal találkozunk, amelyek valahol a kettő között helyezkednek el.
Megjelenítés Latte segítségével
A Latte sablonrendszer 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 megjeleníteni, és ezzel teljes kontrollt szerezni a kód felett. Később megmutatjuk, hogyan lehet ezt a megjelenítést automatizálni.
Az űrlap Latte sablonjának tervét legeneráltathatja a
Nette\Forms\Blueprint::latte($form)
metódussal, amely kiírja azt a böngésző oldalára. A kódot ezután elég
egy kattintással kijelölni és bemásolni a projektbe.
{control}
Az űrlap megjelenítésének legegyszerűbb módja, ha a sablonba beírjuk:
{control signInForm}
Az így megjelenített űrlap kinézetét a Renderer és az egyes elemek konfigurálásával lehet befolyásolni.
n:name
Az űrlap definícióját a PHP kódban rendkívül egyszerűen össze lehet kapcsolni a HTML kóddal. 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 formáját teljes mértékben Ön irányítja. Ha az n:name
attribútumot a
<select>
, <button>
vagy <textarea>
elemeknél használja, azok belső
tartalma automatikusan kiegészül. A <form n:name>
tag ezenkívül létrehoz egy lokális $form
változót a rajzolt űrlap objektumával, és a záró </form>
megjeleníti az összes meg nem jelenített
rejtett elemet (ugyanez érvényes a {form} ... {/form}
-ra is).
Nem szabad azonban elfelejtenünk a lehetséges hibaüzenetek megjelenítését. Mindazokat, amelyeket az
addError()
metódussal adtak hozzá az egyes elemekhez (a {inputError}
segítségével), mindazokat,
amelyeket közvetlenül az űrlaphoz adtak hozzá (ezeket a $form->getOwnErrors()
adja vissza):
<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>
A bonyolultabb űrlap elemeket, mint a RadioList vagy a CheckboxList, így lehet elemenként megjeleníteni:
{foreach $form[gender]->getItems() as $key => $label}
<label n:name="gender:$key"><input n:name="gender:$key"> {$label}</label>
{/foreach}
{label}
{input}
Nem akar minden elemnél azon gondolkodni, hogy milyen HTML elemet használjon hozzá a sablonban, legyen az
<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}
tageken belüli szöveg lefordításra kerül.
Ebben az esetben is a bonyolultabb űrlap elemeket, mint a RadioList vagy a CheckboxList, elemenként lehet megjeleníteni:
{foreach $form[gender]->items as $key => $label}
{label gender:$key}{input gender:$key} {$label}{/label}
{/foreach}
Magának az <input>
elemnek a megjelenítéséhez a Checkbox elemben használja a
{input myCheckbox:}
-t. A HTML attribútumokat ebben az esetben mindig vesszővel válassza el
{input myCheckbox:, class: required}
.
{inputError}
Kiírja a hibaüzenetet az űrlap elemhez, ha van ilyen. Az üzenetet általában HTML elembe csomagoljuk a stílusozás miatt.
Az üres elem megjelenítésének elkerülését, ha nincs üzenet, elegánsan meg lehet oldani az n:ifcontent
segítségével:
<span class=error n:ifcontent>{inputError $input}</span>
A hiba jelenlétét a hasErrors()
metódussal ellenőrizhetjük, és ennek megfelelően beállíthatjuk a szülő
elem osztályát:
<div n:class="$form[username]->hasErrors() ? 'error'">
{input username}
{inputError username}
</div>
{form}
A {form signInForm}...{/form}
tagek alternatívái a
<form n:name="signInForm">...</form>
-nak.
Automatikus megjelenítés
Az {input}
és {label}
tageknek köszönhetően könnyen létrehozhatunk egy általános sablont
bármilyen űrlaphoz. Fokozatosan iterál és megjeleníti az összes elemét, kivéve a rejtett elemeket, amelyek automatikusan
megjelennek az űrlap lezárásakor a </form>
taggel. A megjelenítendő űrlap nevét a $form
változóban fogja várni.
<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 önlezáró páros {label .../}
tagek a PHP kódban lévő űrlap definícióból származó
címkéket jelenítik meg.
Ezt az általános sablont mentse el például a basic-form.latte
fájlba, és az űrlap megjelenítéséhez elég
csak beilleszteni és átadni az űrlap nevét (vagy példányát) a $form
paraméterbe:
{include basic-form.latte, form: signInForm}
Ha egy adott űrlap megjelenítésekor bele szeretne szólni a formájába, és például egy elemet másképp szeretne megjeleníteni, akkor a legegyszerűbb út, ha a sablonban előre elkészít blokkokat, amelyeket később felül lehet írni. A blokkoknak lehetnek dinamikus nevek is, így beléjük lehet illeszteni a megjelenítendő elem nevét is. Például:
...
{label $input /}
{block "input-{$input->name}"}{input $input}{/block}
...
Egy username
nevű elemhez így létrejön az input-username
blokk, amelyet könnyen felül lehet
írni 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 tartalmát definiálni lehet blokként, beleértve a
$form
paramétert is:
{define basic-form, $form}
<form n:name=$form class=form>
...
</form>
{/define}
Ennek köszönhetően kissé egyszerűbb lesz a hívása:
{embed basic-form, signInForm}
...
{/embed}
A blokkot pedig elég egyetlen helyen importálni, a layout sablon elején:
{import basic-form.latte}
Speciális esetek
Ha csak az űrlap belső részét kell megjeleníteni a <form>
HTML tagek nélkül, például snippek
küldésekor, rejtse el őket az 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>
Az elemek megjelenítésében az űrlap konténeren belül segít a {formContainer}
tag.
<p>Melyik híreket szeretné megkapni:</p>
{formContainer emailNews}
<ul>
<li>{input sport} {label sport /}</li>
<li>{input science} {label science /}</li>
</ul>
{/formContainer}
Megjelenítés Latte nélkül
Az űrlap megjelenítésének legegyszerűbb módja a következő hívás:
$form->render();
Az így megjelenített űrlap kinézetét a Renderer és az egyes elemek konfigurálásával lehet befolyásolni.
Manuális megjelenítés
Minden űrlap elem rendelkezik metódusokkal, amelyek generálják az űrlap mező és a címke HTML kódját. Ezt visszaadhatják vagy stringként, vagy Nette\Utils\Html objektumként:
getControl(): Html|string
visszaadja az elem HTML kódjátgetLabel($caption = null): Html|string|null
visszaadja a címke HTML kódját, ha létezik
Az űrlapot így elemenként lehet megjeleníteni:
<?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 egyes elemeknél a getControl()
egyetlen HTML elemet ad vissza (pl. <input>
,
<select>
stb.), másoknál egy egész HTML kódrészletet (CheckboxList, RadioList). Ebben az esetben
használhatja azokat a metódusokat, amelyek az egyes inputokat és címkéket generálják, minden elemhez külön:
getControlPart($key = null): ?Html
visszaadja egy elem HTML kódjátgetLabelPart($key = null): ?Html
visszaadja egy elem címkéjének HTML kódját
Ezeknek a metódusoknak történelmi okokból get
prefixük van, de jobb lenne a
generate
, mert minden híváskor új Html
elemet hoznak létre és adnak vissza.
Renderer
Ez egy objektum, amely biztosítja az űrlap megjelenítését. Ezt a $form->setRenderer
metódussal lehet
beállítani. A vezérlés átadódik neki a $form->render()
metódus hívásakor.
Ha nem állítunk be saját renderert, az alapértelmezett megjelenítő Nette\Forms\Rendering\DefaultFormRenderer kerül felhasználásra. Ez az űrlap elemeit HTML táblázat formájában jeleníti meg. A kimenet így néz ki:
<table>
<tr class="required">
<th><label class="required" for="frm-name">Név:</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">Életkor:</label></th>
<td><input type="text" class="text" name="age" id="frm-age" required value=""></td>
</tr>
<tr>
<th><label>Nem:</label></th>
...
Az, hogy használjunk-e táblázatot az űrlap vázához, vitatható, és sok webdesigner más jelölést részesít előnyben.
Például a definíciós listát. Ezért újrakonfiguráljuk a DefaultFormRenderer
-t úgy, hogy az űrlapot lista
formájában jelenítse meg. A konfiguráció a $wrappers tömb
szerkesztésével történik. Az első index mindig a területet, a második pedig annak attribútumát jelenti. Az egyes
területeket az ábra mutatja:

Alapértelmezés szerint az controls
elemcsoport egy <table>
-ba van csomagolva, minden
pair
egy táblázat sort (<tr>
) képvisel, a label
és control
páros
pedig cellák (<th>
és <td>
). Most megváltoztatjuk a csomagoló elemeket. A
controls
területet egy <dl>
konténerbe helyezzük, a pair
területet konténer
nélkül hagyjuk, a label
-t <dt>
-be, végül a control
-t <dd>
tagekkel csomagoljuk:
$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 ez a HTML kód:
<dl>
<dt><label class="required" for="frm-name">Név:</label></dt>
<dd><input type="text" class="text" name="name" id="frm-name" required value=""></dd>
<dt><label class="required" for="frm-age">Életkor:</label></dt>
<dd><input type="text" class="text" name="age" id="frm-age" required value=""></dd>
<dt><label>Nem:</label></dt>
...
</dl>
A wrappers tömbben számos további attribútumot lehet befolyásolni:
- CSS osztályok hozzáadása az egyes űrlap elem típusokhoz
- CSS osztállyal megkülönböztetni a páros és páratlan sorokat
- vizuálisan megkülönböztetni a kötelező és választható elemeket
- meghatározni, hogy a hibaüzenetek közvetlenül az elemeknél vagy az űrlap felett jelenjenek-e meg
Options
A Renderer viselkedését az egyes űrlap elemeken beállított options segítségével is lehet irányítani. Így lehet beállítani a leírást, amely a beviteli mező mellett jelenik meg:
$form->addText('phone', 'Szám:')
->setOption('description', 'Ez a szám rejtve marad');
Ha HTML tartalmat szeretnénk elhelyezni benne, használjuk a Html osztályt:
use Nette\Utils\Html;
$form->addText('phone', 'Szám:')
->setOption('description', Html::el('p')
->setHtml('<a href="...">A szám megőrzésének feltételei</a>')
);
A Html elemet a címke helyett is lehet használni: $form->addCheckbox('conditions', $label)
.
Elemek csoportosítása
A Renderer lehetővé teszi az elemek vizuális csoportokba (fieldsetekbe) való csoportosítását:
$form->addGroup('Személyes adatok');
Új csoport létrehozása után ez válik aktívvá, és minden újonnan hozzáadott elem egyúttal hozzáadódik ehhez a csoporthoz is. Tehát az űrlapot így lehet építeni:
$form = new Form;
$form->addGroup('Személyes adatok');
$form->addText('name', 'Neved:');
$form->addInteger('age', 'Korod:');
$form->addEmail('email', 'Email:');
$form->addGroup('Szállítási cím');
$form->addCheckbox('send', 'Szállítás címre');
$form->addText('street', 'Utca:');
$form->addText('city', 'Város:');
$form->addSelect('country', 'Ország:', $countries);
A Renderer először a csoportokat jeleníti meg, és csak utána azokat az elemeket, amelyek egyik csoportba sem tartoznak.
Támogatás a Bootstraphez
A példákban találhatók minták arra, hogyan konfigurálja a Renderert a Twitter Bootstrap 2, Bootstrap 3 és Bootstrap 4 számára.
HTML attribútumok
Tetszőleges HTML attribútumok beállításához az űrlap elemekhez használja a
setHtmlAttribute(string $name, $value = true)
metódust:
$form->addInteger('number', 'Szám:')
->setHtmlAttribute('class', 'big-number');
$form->addSelect('rank', 'Rendezés:', ['ár', 'név'])
->setHtmlAttribute('onchange', 'submit()'); // változáskor küldés
// A <form> elem attribútumainak beállításához
$form->setHtmlAttribute('id', 'myForm');
Az elem típusának specifikációja:
$form->addText('tel', 'Telefonod:')
->setHtmlType('tel')
->setHtmlAttribute('placeholder', 'írja be a telefonszámot');
A típus és más attribútumok beállítása csak vizuális célokat szolgál. A bemenetek helyességének ellenőrzése a szerveroldalon kell, hogy történjen, amit a megfelelő űrlap elem kiválasztásával és érvényesítési szabályok megadásával biztosíthat.
A rádió- vagy checkbox listák egyes elemeihez beállíthatunk HTML attribútumot különböző értékekkel mindegyikhez.
Figyelje meg a kettőspontot a style:
után, amely biztosítja az érték kiválasztását kulcs szerint:
$colors = ['r' => 'piros', 'g' => 'zöld', 'b' => 'kék'];
$styles = ['r' => 'background:red', 'g' => 'background:green'];
$form->addCheckboxList('colors', 'Színek:', $colors)
->setHtmlAttribute('style:', $styles);
Kiírja:
<label><input type="checkbox" name="colors[]" style="background:red" value="r">piros</label>
<label><input type="checkbox" name="colors[]" style="background:green" value="g">zöld</label>
<label><input type="checkbox" name="colors[]" value="b">kék</label>
Logikai attribútumok, mint a readonly
, beállításához használhatunk kérdőjeles írásmódot:
$form->addCheckboxList('colors', 'Színek:', $colors)
->setHtmlAttribute('readonly?', 'r'); // több kulcshoz használjon tömböt, pl. ['r', 'g']
Kiírja:
<label><input type="checkbox" name="colors[]" readonly value="r">piros</label>
<label><input type="checkbox" name="colors[]" value="g">zöld</label>
<label><input type="checkbox" name="colors[]" value="b">kék</label>
Select boxok esetén a setHtmlAttribute()
metódus a <select>
elem attribútumait állítja be.
Ha az egyes <option>
elemek attribútumait szeretnénk beállítani, használjuk a
setOptionAttribute()
metódust. Működnek a fentebb említett kettőspontos és kérdőjeles írásmódok is:
$form->addSelect('colors', 'Színek:', $colors)
->setOptionAttribute('style:', $styles);
Kiírja:
<select name="colors">
<option value="r" style="background:red">piros</option>
<option value="g" style="background:green">zöld</option>
<option value="b">kék</option>
</select>
Prototípusok
A HTML attribútumok beállításának alternatív módja a minta módosítása, amelyből a HTML elem generálódik. A minta
egy Html
objektum, és a getControlPrototype()
metódus adja vissza:
$input = $form->addInteger('number', 'Szám:');
$html = $input->getControlPrototype(); // <input>
$html->class('big-number'); // <input class="big-number">
Ezzel a módszerrel módosítható a címke mintája is, amelyet a getLabelPrototype()
ad vissza:
$html = $input->getLabelPrototype(); // <label>
$html->class('distinctive'); // <label class="distinctive">
A Checkbox, CheckboxList és RadioList elemeknél befolyásolhatja annak az elemnek a mintáját, amely az egész elemet
csomagolja. Ezt a getContainerPrototype()
adja vissza. Alapértelmezett állapotban ez egy „üres” elem, tehát
semmi sem jelenik meg, de azzal, hogy nevet adunk neki, megjelenítésre kerül:
$input = $form->addCheckbox('send');
$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>
CheckboxList és RadioList esetén befolyásolható az egyes elemek elválasztójának mintája is, amelyet a
getSeparatorPrototype()
metódus ad vissza. Alapértelmezett állapotban ez a <br>
elem. Ha páros
elemre változtatja, akkor az egyes elemeket csomagolni fogja elválasztás helyett. Továbbá befolyásolható az egyes elemek
címkéjének HTML elem mintája is, amelyet a getItemLabelPrototype()
ad vissza.
Fordítás
Ha többnyelvű alkalmazást programoz, valószínűleg szüksége lesz az űrlap különböző nyelvi változatokban történő megjelenítésére. A Nette Framework ehhez definiál egy fordítási interfészt Nette\Localization\Translator. A Nette-ben nincs alapértelmezett implementáció, választhat igényei szerint több kész megoldás közül, amelyeket a Componette oldalon talál. Dokumentációjukban megtudhatja, hogyan konfigurálja a fordítót.
Az űrlapok támogatják a szövegek fordítón keresztüli kiírását. Ezt a setTranslator()
metódussal adjuk
át nekik:
$form->setTranslator($translator);
Ettől a pillanattól kezdve nemcsak az összes címke, hanem az összes hibaüzenet vagy select box elem is lefordításra kerül egy másik nyelvre.
Az egyes űrlap elemeknél lehetőség van más fordító beállítására vagy a fordítás teljes kikapcsolására
null
értékkel:
$form->addSelect('carModel', 'Modell:', $cars)
->setTranslator(null);
Az érvényesítési szabályoknál a fordítónak specifikus paraméterek is átadásra kerülnek, például a szabálynál:
$form->addPassword('password', 'Jelszó:')
->addRule($form::MinLength, 'A jelszónak legalább %d karakter hosszúnak kell lennie', 8);
a fordító ezekkel a paraméterekkel hívódik meg:
$translator->translate('A jelszónak legalább %d karakter hosszúnak kell lennie', 8);
és így kiválaszthatja a karakter
szó helyes többes számú alakját a szám alapján.
onRender esemény
Közvetlenül azelőtt, hogy az űrlap megjelenne, meghívathatjuk a kódunkat. Ez például kiegészítheti az űrlap elemeket
HTML osztályokkal a helyes megjelenítés érdekében. A kódot az onRender
tömbhöz adjuk hozzá:
$form->onRender[] = function ($form) {
BootstrapCSS::initialize($form);
};