Návrh různých vylepšení formulářů

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
mkrause
Člen | 20
+
0
-

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.
LM
Člen | 206
+
0
-

Label je lepší získat takto:

$control->getLabel()->getText();

Jinak David mluvil ještě o dalším konfigurovatelném renderu formulářů, ale ještě není v distribuci.

David Grudl
Nette Core | 8228
+
0
-

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
+
0
-

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
+
0
-

Titulek a orámování (tj. legend & fieldset) vyrobíš pomocí skupin. Zkus se podívat v distribuci na examples/forms.

mkrause
Člen | 20
+
0
-

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í :)