Vlastní HTML v Rendereru při generování formulářových prvků
- martin.loucka
- Člen | 9
Dobrý den,
mám problém s generováním kódu formuláře v Nette. Předesílám, že jsem v Nette začátečník, proto nemám úplný přehled o možnostech tvorby odvozených tříd apod.
Vzhledem k tomu, že nevím přesně, kde je jádro problému, půjdu raději rovnou k věci, a to formou názorného příkladu.
Při definování formuláře v metodě v Presenteru použiji následující kód:
$form = new UI\Form;
$form->addRadioList('gender', 'Pohlaví:', array('m'=>'muž','f'=>'žena'));
return $form;
V šabloně v rámci procházení {form} použiji:
<div n:foreach="$form->controls as $input" class="row form-group">
{label $input, class => 'col-sm-2 control-label' /}
<div class="col-sm-10">
{input $input, class => 'form-control'}
</div>
</div>
Dostanu při použití výchozího Rendereru toto HTML:
<div class="row form-group ">
<label class="col-sm-2 control-label">Pohlaví:</label>
<div class="col-sm-10">
<label for="frm-contactForm-gender-m">
<input type="radio" name="gender" id="frm-contactForm-gender-m" value="m">muž
</label>
<br>
<label for="frm-contactForm-gender-f">
<input type="radio" name="gender" id="frm-contactForm-gender-f" value="f">žena
</label>
</div>
</div>
Otázka je prostá, lze nějakým způsobem (a jakým) zanést do Nette nový vzor generování Radio tak, aby výsledný efekt vypadal takto?
<div class="row form-group ">
<label class="col-sm-2 control-label">Pohlaví:</label>
<div class="col-sm-10">
<div class="radio">
<label for="frm-contactForm-gender-m">
<input type="radio" name="optionsRadios" id="optionsRadios1" value="m" class="px">
<span class="lbl">muž</span>
</label>
</div>
<div class="radio">
<label for="frm-contactForm-gender-f">
<input type="radio" name="optionsRadios" id="optionsRadios2" value="f" class="px">
<span class="lbl">žena</span>
</label>
</div>
</div>
</div>
Jde mi zejména o to, kde je onen standardní template pro renderování definován a jak ho ideálně pro své účely upravit (nejlépe zřejmě v nějaké odvozené třídě).
Mockrát děkuji!
- David Kudera
- Člen | 455
Ahoj, koukni na tento článek. Jsou tam přesně věci, co potřebuješ. I s odkazem na kód pro renderování s bootstrapem, který by ti nakonec mohl třeba i stačit úplně
- martin.loucka
- Člen | 9
Mockrát děkuji za odpověď.
Ten odkazovaný článek jsem procházel už prve – chápu, že je určen pro řešení tohoto typu problému, ale ten můj neřeší (ani ta vzorová integrace s Bootstrap3) úplně. Se dvěma drobnými úpravami se to tomu již velice blíží, ale zásadní problém, který teď řeším je jak přidat nový element, který bude v RadioListu obalovat popisek toho samotného Radia. Opět příklad :)
Již mám
<div class="form-group">
<div class="col-sm-2 control-label"><label>Your gender</label></div>
<div class="col-sm-10">
<div class="radio">
<label for="frm-contactForm-gender-0">
<input type="radio" name="gender" class="px lbl" id="frm-contactForm-gender-0" value="0">
male
</label>
</div>
(...)
</div>
A potřebuji přidat jeden obalovací <span class="lbl">
okolo toho výrazu „male“, aby to vypadalo takto:
<div class="form-group">
<div class="col-sm-2 control-label"><label>Your gender</label></div>
<div class="col-sm-10">
<div class="radio">
<label for="frm-contactForm-gender-0">
<input type="radio" name="gender" class="px lbl" id="frm-contactForm-gender-0" value="0">
<span class="lbl">male</span>
</label>
</div>
(...)
</div>
Hraju si s kódem z odkazovaného článku, který má zajišťovat integraci s Bootstrapem, umím si upravit stávající elementy, ale nemůžu přijít na to, jak na toto specifické místo vložit nový.
Zkoušel jsem přidat do kódu v rámci té podmínky pro RadioList
$control->getControlPrototype()->add('span')->addClass('lbl');
ale to mi vůbec nezměnilo kód stránky.
- David Kudera
- Člen | 455
Tak to mě napadá vytvořit si vlastní form renderer, který dědí od toho základního . No a v něm bych rozšířil metodu renderControl .
Jen to taky nebude úplně na jeden řádek nejspíš.. Vykreslení samotného radia je zvlášť , tak jako všech ostatních prvků.
No a nebo to udělat v té šabloně všechno, dát do toho cyklu, co máš v šabloně velmi nehezkou podmínku, která zjistí, jestli je to radio a u něj provede to, co je v článku výše pojmenováno jako „partial rendering“. Asi bych to tak i nakonec udělal, i když se mi nelíbí ta podmínka instanceof v šabloně..
- martin.loucka
- Člen | 9
Tak jsem nakonec našel ještě jedno podobné téma zde na fóru a využil modifikaci Rendereru navrhovanou v odpovědi.
Případně pro ostatní uvádím postup, jak jsem integraci Bootstrap šablony nakonec řešil já:
Do BasePresenteru jsem si vytvořil metodu polishForm($form)
,
které se předá objekt formuláře a ona na něj aplikuje tu bootstrapáckou
konfiguraci odsud.
Ten kousek kódu z odkazovaného vlákna jsem dal do isset
u,
aby se spouštěl jen, má-li co udělat a vložil do podmínky pro RadioList
z výše odkazovaného gitu:
if(isset($control->items))
if($control instanceof Controls\RadioList) {
$control->items = array_map(function($value) {
return Html::el('span')->setText($value);
}, $control->items);
}
else $control->caption = Html::el('span')->addClass('lbl')->setText($control->caption);
A když vytvářím formulář pomocí
createComponent<FormName>()
, tak nakonec místo
return $form
dám return $this->polishForm($form)
a
vypisuji normálně v latte pomocí
{form 'nazev'}{? echo $form}{/form}
.
Je to jednodušší, než vytvářet novou komponentu v latte, na druhou stranu teď budu řešit problém s client-side validací, který bude asi dost nepříjemný, vzhledem k tomu, že ta šablona má i svoje prvky na tohle…
Editoval martin.loucka (5. 8. 2014 15:27)
- David Kudera
- Člen | 455
Jedna věc, určitě bych to nenechával na presenteru. Ten by měl být správně co nejužší a nejjednodušší. Můžeš si ale vytvořit jednoduchou tovární třídu na formuláře, která formulář vytvoří, nastaví tvůj renderer a vrátí jej. Dobré je tohle ve spojení s vlastní komponentou pro formuláře zvlášť. Tady se nedávno řešili formuláře jako samostatné komponenty