Vlastní HTML v Rendereru při generování formulářových prvků

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

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

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

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

A má se tak dít automaticky vždy pro úplně všechny radia?

martin.loucka
Člen | 9
+
0
-

Ano, má; všechny formuláře bych rád měl stejné.

David Kudera
Člen | 455
+
0
-

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

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

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