Návrh různých vylepšení formulářů
- mkrause
- Člen | 20
Ahoj Davide, předem díky za nové funkce z poslední doby, zejména renderery formulářů nás potěšily :) Na základě relativně intenzivního používání formulářů a krátkodobého zkoumání rendererů bych si dovolil navrhnout pár úprav.
Formulářová pole (potomci FormControl):
- řada atributů je privátních, což poněkud komplikuje vytváření potomků. Panuje v tom navíc dle mého názoru trochu schizofrenní přístup, kdy například SelectBox má atribut items privátní a ostatní atributy protected. Klonil bych se k protected u všeho. Podobně jsme narazili u třídy HttpUploadedFile, ale to už byl asi dost specifický případ.
- pole neuchovávají původní label (jen HTML element pro jeho vizuální
reprezentaci). Možnost získat původní „holý“ řetězec by se občas
hodila. Narazil jsem na to už ve dvou případech: poprvé, když se
k předpřipraveným polím později automaticky přidává typová validace
dle databáze (nelze vytvořit chybovou hlášku s labelem), a podruhé, když
se mají data z formuláře vložit do emailu (takové to klasické „vaše
objednávka byla přijata s těmito údaji: Jméno: xxx …“). Dá se
použít něco jako
striptags((string) $control->getLabel())
, ale je to ošklivé.
Renderery:
- přimlouval bych se za jemnější rozdělení funkčnosti třidy
ConventionalRenderer do více metod. Přijde mi, že se velmi často v designu
formulářů řeší jen drobnosti typu „chci pod input vypsat krátkou
nápovědu“ a podobně, takže ConventionalRenderer je plně vyhovující, jen
je třeba se někam drobně vmísit s vlastní funkčností. Přišlo by mi
šikovné, kdyby například metoda renderControls volala metody pro vytvoření
pairu, labelu a controlu, takže její potomek by jednoduše přepsal jednu
metodu, kde by namísto
$control->getControl()
vracel něco jako$desc = Html::el("span")->setText($help);
Html::el("")->add($control->getControl())->add($desc);
. Teď to lze řešit buďto přepsáním celé metody renderControls, která toho ale dělá hodně, takže by se celá zkopírovala z předka a s dalšími verzemi by se mohla odchylovat od zamýšleného chování, a nebo vytvořením zcela nového rendereru, což ale není zrovna triviální. Druhou možností by asi bylo nechat ConventionalRenderer v současné podobě jakožto konfigurovatelnou variantu, a vytvořit jiný abstraktní renderer coby kostru určenou pro rozšiřování, kde by se už uživatel nemusel tolik zabývat různými specialitami, jako jsou klientské javascripty atd.
- David Grudl
- Nette Core | 8228
mkrause napsal(a):
Ahoj Davide, předem díky za nové funkce
To je nádherně manipulující formulace :-)))
Formulářová pole (potomci FormControl):
- řada atributů je privátních, což poněkud komplikuje vytváření potomků. Panuje v tom navíc dle mého názoru trochu schizofrenní přístup.
To je možné – Jde o důsledek používání interního návrhového vzoru „Zakaž vše, povol až narazíš“ ;) Protože sám prvky formuláře nerozšiřuju, neznám úskalí.
kdy například SelectBox má atribut items privátní a ostatní atributy protected. Klonil bych se k protected u všeho. Podobně jsme narazili u třídy HttpUploadedFile, ale to už byl asi dost specifický případ.
Aha, tak to mi uniklo, hned ty protected opravím na private :-) Ne vážně, to chce řešit kus od kusu, nastavit vše na protected není rozumné. Obecně, pokud třída nabízí getter (a setter), neměl by být s private problém, ne? Některé protected prvky existují spíš jen z optimalizačních důvodů, např. FormControl::$control a FormControl::$label, obojí by však mělo být spíš private a přístupné přes getControlPrototype() a getLabelPrototype(). Nebo SelectBox::$items má getter getItems(), tudíž by nemělo private vadit.
Zkus mi tedy spíš napsat konkrétně, na co jste narazili, pořešíme to koncepčně.
- pole neuchovávají původní label (jen HTML element pro jeho vizuální reprezentaci). Možnost získat původní „holý“ řetězec by se občas hodila.
Já vím, to chci pořešit. Zatím tedy přes
$control->label->text
.
Renderery:
- přimlouval bych se za jemnější rozdělení funkčnosti třidy ConventionalRenderer do více metod. Přijde mi, že se velmi často v designu formulářů řeší jen drobnosti typu „chci pod input vypsat krátkou nápovědu“ a podobně, takže ConventionalRenderer je plně vyhovující, jen je třeba se někam drobně vmísit s vlastní funkčností.
Pro předávání parametrů mezi vlastní funkčností a formulářovými prvky se dá využít $control->setOption() a getOption().
Přišlo by mi šikovné, kdyby například metoda renderControls volala metody pro vytvoření pairu, labelu a controlu, takže její potomek by jednoduše přepsal jednu metodu, kde by namísto
$control->getControl()
vracel něco jako$desc = Html::el("span")->setText($help);
Html::el("")->add($control->getControl())->add($desc);
. Teď to lze řešit buďto přepsáním celé metody renderControls, která toho ale dělá hodně,
Ok, zjemnil jsem renderControls, do dalších 4 metod.
nebo vytvořením zcela nového rendereru, což ale není zrovna triviální.
To mám v plánu, ale nebude to hned.
- Marcel
- Člen | 6
ahoj,
zopar napadov co som vo formoch nenasiel a mozno by sa to hodilo viacerim (mozno
to tam je, ale…):
- chyba mi nadpis/titulok formularu
- ku komponentom formularu by sa mi celkom hodil aj komponent staticky text (asi sa to da obist cez textareu a nejaky custom renderer, ale je to dost nepriamociare riesenie)
- David Grudl
- Nette Core | 8228
Titulek a orámování (tj. legend & fieldset) vyrobíš pomocí skupin. Zkus se podívat v distribuci na
examples/forms
.
- mkrause
- Člen | 20
Ahoj, vracím se k tomu po delší době, protože mě od toho odvedly jiné úkoly :)
Jemnější rozdělení metod v rendereru je prima, zvlášť v kombinaci s getOption/setOption u formulářových prvků.
Pokud jde o přístupnost atributů, máš asi pravdu – většinu věcí jsem dokázal vyřešit s pomocí getterů a setterů, takže větší přístupnost není nutná.
Takže díky za tipy a vylepšení :)