Latte / Formulář – manuální vykreslení pouze jednoho prvku formuláře
- emololftw
- Člen | 82
Ahoj komunito,
projekt obsahuje opravdu velký formulář generovaný skrze
nette/forms
Je možnost manuálně vykreslit pouze jeden jediný prvek formuláře? Chci se
vyhnout kvůli jednomu prvku renderování celého formuláře.
Něco ve stylu:
{form orderForm}
{define frm-orderDate-pair}
....
{/define}
{control $form}
{/form}
- Kamil Valenta
- Člen | 822
Ne, ale můžeš si pomocí printForm zobrazit, co by automatický render vygeneroval, zkopírovat a upravit ten jeden input…
- m.brecher
- Generous Backer | 873
@KamilValenta
Ahoj, vykreslování formulářů je v Nette docela problém. Defaultní renderer má nepříjemné nedodělky z hlediska frontendu a na složitější věci použít nejde. Generovat kód pro každý formulář a provést následné úpravy by bylo použitelné, kdyby nenásledovaly další a další změny ve struktuře databáze, což u inovativních projektů je velmi běžné.
Jako Nette nováček zkouším tohle nějak vyřešit a snažím se napsat si nějakou šikovnou latte šablonu, která by umožnila:
- automatické vykreslování jakýchkoliv formulářů
- možnost kterou by uvítal @emololftw – definovat pro konkrétní prvek vlastní html/latte šablonu
ale zatím jsem ve fázi pokusů.
Jak u Vás ve firmě tohle máte vyřešené (komponenty pomocí trait jste vymysleli hezky – viz naše minulá diskuze)?
- David Grudl
- Nette Core | 8239
Já v tom žádný problém nevidím. Proč bych měl s úpravou databáze
měnit kód? Prostě si vyrobím jednoduchou šablonu, která vygeneruje
jakýkoliv formulář a uložím ji do basic-form.latte
.
<form n:name=$form>
<ul class=error n:ifcontent>
<li n:foreach="$form->ownErrors as $error">{$error}</li>
</ul>
<table>
<tr n:foreach="$form->controls as $input"
n:if="!$input->getOption(rendered) && $input->getOption(type) !== hidden"
n:class="$input->required ? required">
<th>{label $input /}</th>
<td>{input $input} <span class=error n:ifcontent>{$input->error}</span></td>
</tr>
</table>
</form>
Pak stačí ji zavolat a předat název nebo instanci formuláře do
proměnné form
:
{include basic-form.latte, form: myFormName}
Chci vykreslit nějaký prvek jinak? Upravím šablonu
basic-form.latte
tak, že si v ní připravím bloky, které pak
můžu přepsat, viz dědičnost šablon.
Bloky můžou mít klidně dynamický
název, můžu do nich zakomponovat jméno vykreslovaného prvku.
Takže třeba:
...
<th n:inner-block="label-{$input->name}">{label $input /}</th>
<td n:inner-block="input-{$input->name}">{input $input} <span class=error n:ifcontent>{$input->error}</span></td>
...
Pro prvek např. orderDate
tak vzniknou bloky
label-orderDate
a input-orderDate
, které můžu
snadno přepsat použitím značky embed:
{embed basic-form.latte, form: myFormName}
{block input-orderDate}
nový obsah pred inputem
{include parent}
nový obsah za inputem
{/block}
{/embed}
Nelíbí se mi uvádět všude cestu k souboru basic-form.latte
a název parametru form:
? Tak z toho udělám
blok a název parametru zadefinuji:
{define basic-form $form}
<form n:name=$form>
<ul class=error n:ifcontent>
<li n:foreach="$form->ownErrors as $error">{$error}</li>
</ul>
<table>
<tr n:foreach="$form->controls as $input"
n:if="!$input->getOption(rendered) && $input->getOption(type) !== hidden"
n:class="$input->required ? required">
<th n:inner-block="label-{$input->name}">{label $input /}</th>
<td n:inner-block="input-{$input->name}">{input $input} <span class=error n:ifcontent>{$input->error}</span></td>
</tr>
</table>
</form>
{/define}
Tento blok načtu pomocí značky import a stačí to udělat pouze v
@layout.latte
:
{import basic-form.latte}
A pak bude stačit psát:
{include basic-form myFormName}
nebo
{embed basic-form myFormName}
...
{/embed}
Jestli vás napadá, jak by to mohlo jít lépe nebo jednodušeji, klidně dejte vědět, mě ne.
- Kamil Valenta
- Člen | 822
m.brecher napsal(a):
Jak u Vás ve firmě tohle máte vyřešené (komponenty pomocí trait jste vymysleli hezky – viz naše minulá diskuze) ??
Popravdě nijak. Samotný form (coby komponenta) se generuje automaticky ze struktury databáze, tohle ušetří mnoho práce. Ale šablony, ty už píšeme ručně. Sázíme formuláře do gridu a nejde moc automaticky říct, kolik col-N bude který input mít. Navíc do toho vstupují různé buttony u labelů, nápovědy, náhledy u uploadů. Stejně bychom nějakou obecnou šablonu přepisovali pro každý form. Je naprosté minimum formulářů, které by vystačily s automatickým renderem. A kvůli nim se neoplatí udržovat nějakou mašinérii. Takže u nás zatím vede manuální render.
P.S. na traitách jsme nic nevymysleli :) jen je používáme.
- m.brecher
- Generous Backer | 873
@KamilValenta
Díky za zajímavé informace,
Samotný form (coby komponenta) se generuje automaticky ze struktury databáze
Tohle je zajímavý postup, to by mě blíže zajímalo. Neposlal by Jsi sem nějaký příklad kódu jak to konkrétně děláte? Co validační pravidla, co defaultní hodnoty prvků, co chybové hlášky – tohle všechno generujete automaticky, aniž by jste museli ručně psát $form pro každý prvek?
Takže u nás zatím vede manuální render.
OK, je to hromada ruční práce, ale vede to k cíli.
- Kamil Valenta
- Člen | 822
m.brecher napsal(a):
Samotný form (coby komponenta) se generuje automaticky ze struktury databáze
Tohle je zajímavý postup, to by mě blíže zajímalo. Neposlal by Jsi sem nějaký příklad kódu jak to konkrétně děláte ??
$form = new Form;
$form->table('article')
->without('image')
->generate();
$form->addUpload('image', 'Obrázek');
$form->onSuccess[] = [$this, 'formSucceeded'];
return $form;
Můžeš si takhle z té automatiky nějaké sloupce vyhodit a doplnit
ručně, protože třeba ‚image‘ je VARCHAR a vygeneroval by se jak
input=text.
Jinak je to celkem přímočaré, umí to text (i s modifikací date a time),
textArea, checkbox (ten se generuje z tinyINT). Pokud to narazí v db na FK,
udělá se číselník v selectu.
Co validační pravidla,
Drtivá většina je zadána již omezením v db, takže se vygenerují
taky. A pokud chceš připsat nějaké vlastní (děje se velmi zřídka),
vždy můžeš přes $form[‚name‘]->addRule()
SetNullable() a setRequired() také poznáš už z db.
co defaultní hodnoty prvků,
Pokud formuláři nepředáš nějaké id, vezme defaultní hodnoty
z db.
Pokud předáš, načte danou větu z tabulky.
co chybové hlášky
Ty tak jako tak tečou přes translator, takže se nagenerují samy z názvu tabulky a sloupce a zbytek řeší překlad
Takže u nás zatím vede manuální render.
OK, je to hromada ruční práce, ale vede to k cíli.
Sám přemýšlím k tomu znásilnit třeba komentáře v tabulce, ale jak jsem psal, nejde jen o sazbu, jde o různé prvky kolem inputů a stejně by se do toho furt muselo sahat. Oproti tomu napsat šablonu pro form je otázka chvilky – třebaže rutinní práce.
Editoval Kamil Valenta (1. 1. 2023 9:35)
- Bulldog
- Člen | 110
@KamilValenta Taky používáme na pár projektech automatické generování formulářů.
Místo datového typu z databáze ale máme v tabulce u sloupečků poznámku, kterou využíváme na přesnější definici co vlastně za prvek má být použito a popřípadě i dodatečná validační pravidla.
Viděl jsem to už i způsoby, že pro formuláře byla separátní tabulka, kde každý řádek byl definice formuláře pro každou tabulku, kde to chtěli lidi využít, ale to mi zase přišlo zbytečné.
- m.brecher
- Generous Backer | 873
@KamilValenta díky, ta třída Form by mě také zajímala blíže, také o něčem takovém uvažuji
checkbox (ten se generuje z tinyINT)
Také jsem pro boolean v mySql používal tinyint, ale nedávno jsem přešel na bit(1) který má může mít jenom dvě hodnoty – 0 nebo 1.
@Bulldog
Místo datového typu z databáze ale máme v tabulce u sloupečků poznámku, kterou využíváme na přesnější definici co vlastně za prvek má být použito a popřípadě i dodatečná validační pravidla.
To by mě zajímalo, jak to máte vymyšlené Vy, nemáš někde nějakou ukázku kódu?
- Kamil Valenta
- Člen | 822
m.brecher napsal(a):
Také jsem pro boolean v mySql používal tinyint, ale nedávno jsem přešel na bit(1) který má může mít jenom dvě hodnoty – 0 nebo 1.
Kvůli kompatibilitě s některými nástroji používáme TINYINT(1). A tuším i některými exporty, kde BIT zlobil. Ale úplně nesleduji, zda ty důvody už všechny nevzal čas. Nedělal jsem ani test, zda je na tom výkonově BIT pro 1 bool nějak lépe.
@mystik @mbrecher Ta třída nikde veřejně není, popravdě obsahuje i dost interních věcí kolem, bylo by hezké to někdy učesat, ale není to v prioritách. Můžeme se ale domluvit bokem a obecné části si ukázat.
- Kamil Valenta
- Člen | 822
Je to opět trochu akademická debata a moc ji nechci rozjíždět (o to
víc ve vlákně o manuálním vykreslování formů).
Oni se ani ti vývojáři MySQL nevydali tou „jedinou logicky správnou
volbou“.
https://dev.mysql.com/…a-types.html
BIT alespoň v minulosti nebyl bezpečnou volbou pro přenositelnost mezi
OS, mezi verzemi MySQL ani RDBMS. Nesleduji, zda má MySQL vyřešené všechny
bugy kolem LEFT JOINů přes BIT sloupec.
Spíš je otázka, co to praktického přinese, krom těch rizik. Stejně se
oboje uloží na 1 byte.
Na nástroje už asi nevzpomenu, je to dost let zpět. Možná Workbench, možná MySQL Administrator. Nevím, roky už používáme Heidi.