Změna renderování checkboxu uvnitř Label

- ajda2
 - Člen | 66
 
Zdravím Vás,
narazil jsem na menší problém při tvorbě „vlastního“ rendereru pro
formuláře.
Mým cílem je změnit výchozí vykreslování checkboxu uvnitř labelu na
tento tvar:
<label for="checkbox-id">
	<input type="checkbox" name="active" id="checkbox-id">
	<span class="nejaka-trida">TENTO SPAN CHCI VLOŽIT VČETNĚ TŘÍDY</span>
	Label checkboxu
</label>
Za tímto účelem jsem si vytvořil vlastní renderer, který dědí od https://api.nette.org/…enderer.html
abych nemusel začínat na zelené louce.
Přetížil jsem metodu renderControl, abych v ní vložil do
labelu svůj kýžený span.
Zde jsem právě narazil na problém.
<?php
$el = $control->getControl();
if ($el instanceof Html && $el->getName() === 'input') {
	$el->class($this->getValue("control .$el->type"), TRUE);
}
return $body->setHtml($el . $description . $this->renderErrors($control));
?>
Konkrétně volání metody getControl() způsobí, že
veškeré mnou vložené HTML elementy do Labelu jsou nenávratně ztraceny,
protože se nastaví HTML obsah docela brutálním způsobem napřímo pomocí
metody setHtml jako řetězec a není jej možné poté snadno
editovat, protože veškerý obsah je řetězec.
Viz https://api.nette.org/…box.php.html#…
Nenapadá někoho prosím nějaké jednoduché řešení, jak vložit
nějaký HTML obsah dovnitř Label za samotný checkbox?
Řešením by nejspíš bylo změnit drastické vkládání HTML obsahu skrze
metodu setHtml a nahradit ji insert, nebo
add, ale vytvářet vlastní checkBox třídu a vlastní Form,
který jej bude používat mi přijde zbytečně pracné.
Předem děkuji za pomoc a rady.
Editoval ajda2 (30. 6. 2016 8:36)

- Oli
 - Člen | 1215
 
Jde změnit nějak líp renderování checkboxu (selectu, radio listu)?
Potřeboval bych kvůli material designu například aby v checkboxu input nebyl
obalenej labelem. Renderer jsem si napsal, ale do něj jde z Control\Checkbox
už hotovej řetězec
<label><input/></label>.
To by znamenalo napsat vlastní implementaci
Control\Checkboxu a UI\Form. Pokud bych chtěl ale
použít jinej form, musel bych to definovat znovu, takže vlastně bych měl
udělat i vlastní Form\Form a Forms\Container.
Není to trochu zbytečné? Neexistuje nějaký parametr, něco, který by zajistil, že se input nebude obalovat do label?
EDIT:
Jak to tak bývá, sotva se zeptám, najdu řešení. Checkbox i radio list
mají metodu getControlPart a getLabelPart. Takže pak
stačí v renderControl něco takového:
if ($control instanceof Nette\Forms\Controls\Checkbox)
{
    $el = $control->getControlPart();
} else {
    $el = $control->getControl();
}
					Editoval Oli (15. 11. 2016 8:29)

- steelbull
 - Člen | 244
 
@Oli Presne to isté by som potreboval aj ja, vyriešil si to nejako?
Oli napsal(a):
Jde změnit nějak líp renderování checkboxu (selectu, radio listu)?
Potřeboval bych kvůli material designu například aby v checkboxu input nebyl obalenej labelem. Renderer jsem si napsal, ale do něj jde z Control\Checkbox už hotovej řetězec
<label><input/></label>.To by znamenalo napsat vlastní implementaci
Control\Checkboxu aUI\Form. Pokud bych chtěl ale použít jinej form, musel bych to definovat znovu, takže vlastně bych měl udělat i vlastníForm\FormaForms\Container.Není to trochu zbytečné? Neexistuje nějaký parametr, něco, který by zajistil, že se input nebude obalovat do label?
EDIT:
Jak to tak bývá, sotva se zeptám, najdu řešení. Checkbox i radio list mají metodu
getControlPartagetLabelPart. Takže pak stačí v renderControl něco takového:if ($control instanceof Nette\Forms\Controls\Checkbox) { $el = $control->getControlPart(); } else { $el = $control->getControl(); }
Editoval steelbull (25. 2. 2018 10:20)

- steelbull
 - Člen | 244
 
@Oli Ja potrebujem vyrenderovať toto:
    <input type="checkbox" id="1" class="k-checkbox" checked="checked">
    <label class="k-checkbox-label" for="1">Rear side airbags</label>
Oli napsal(a):
Jde změnit nějak líp renderování checkboxu (selectu, radio listu)?
Potřeboval bych kvůli material designu například aby v checkboxu input nebyl obalenej labelem. Renderer jsem si napsal, ale do něj jde z Control\Checkbox už hotovej řetězec
<label><input/></label>.To by znamenalo napsat vlastní implementaci
Control\Checkboxu aUI\Form. Pokud bych chtěl ale použít jinej form, musel bych to definovat znovu, takže vlastně bych měl udělat i vlastníForm\FormaForms\Container.Není to trochu zbytečné? Neexistuje nějaký parametr, něco, který by zajistil, že se input nebude obalovat do label?
EDIT:
Jak to tak bývá, sotva se zeptám, najdu řešení. Checkbox i radio list mají metodu
getControlPartagetLabelPart. Takže pak stačí v renderControl něco takového:if ($control instanceof Nette\Forms\Controls\Checkbox) { $el = $control->getControlPart(); } else { $el = $control->getControl(); }

- jurajkovac
 - Člen | 2
 
Tu je riešenie, ak sa nájde niekto ďalší, kto potrebuje vykresľovať checkbox/radio button a label za sebou.
1. Jednoduchá, ale pracnejšia cesta: low-level
rendering
Namiesto prostého {control myForm} si všetko
vymenujem ručne:
{form myForm}
	{input choices:itemA}{label choices:itemA /}
	{input choices:itemB}{label choices:itemB /}
	...
{/form}
Samozrejme je možné to zabaliť do cyklu a vymenovať automaticky:
{form myForm}
	{foreach $form['choices']->items as $key => $label}
		{input choices:$key}{label choices:$key /}
	{/foreach}
{/form}
2. Náročnejšia, ale udržateľnejšia cesta: custom
renderer
Vytvorím si vlastný form renderer, ktorý zdedí všetky schopnosti od
DefaultFormRenderer, avšak pre radio buttons a checkboxy bude
uplatňovať vlastnú logiku vykresľovania.
Vytvorím si teda novú triedu ako extension
Nette\Forms\Rendering\DefaultFormRenderer a úplne stačí, aby
obsahovala jedinú metódu: renderControl()
Ideálne skopírovať ju kompletne z DefaultFormRendereru a len v nej
ošetríme konkrétne prípady pre RadioList a Checkbox:
class myFormRenderer extends Nette\Forms\Rendering\DefaultFormRenderer
	public function renderControl(Nette\Forms\IControl $control) {
		...
		$control->setOption('rendered', true);
		// Is this an instance of a RadioList or Checkbox?
		if ($control instanceof Nette\Forms\Controls\Checkbox || $control instanceof Nette\Forms\Controls\RadioList) {
			// Create an empty Html container object
			$el = Html::el();
			// Get all the child items
			$items = $control->getItems();
			// For each child item, add the appropriate control part and label part after one another
			foreach($items as $key => $item) {
				$el->addHtml($control->getControlPart($key));
				$el->addHtml($control->getLabelPart($key));
			}
		// For all other control types, revert to default functionality
		} else {
			$el = $control->getControl();
		}
		...
	}
Snáď to pomôže každému, kto potrebuje použiteľný
input[type=radio]+label CSS selektor.
Poďakovanie patrí @Oli, ktorý ma priviedol na správnu stopu.

- steelbull
 - Člen | 244
 
jurajkovac napsal(a):
Tu je riešenie, ak sa nájde niekto ďalší, kto potrebuje vykresľovať checkbox/radio button a label za sebou.
1. Jednoduchá, ale pracnejšia cesta: low-level rendering
Namiesto prostého{control myForm}si všetko vymenujem ručne:{form myForm} {input choices:itemA}{label choices:itemA /} {input choices:itemB}{label choices:itemB /} ... {/form}Samozrejme je možné to zabaliť do cyklu a vymenovať automaticky:
{form myForm} {foreach $form['choices']->items as $key => $label} {input choices:$key}{label choices:$key /} {/foreach} {/form}2. Náročnejšia, ale udržateľnejšia cesta: custom renderer
Vytvorím si vlastný form renderer, ktorý zdedí všetky schopnosti odDefaultFormRenderer, avšak pre radio buttons a checkboxy bude uplatňovať vlastnú logiku vykresľovania.Vytvorím si teda novú triedu ako extension
Nette\Forms\Rendering\DefaultFormRenderera úplne stačí, aby obsahovala jedinú metódu:renderControl()
Ideálne skopírovať ju kompletne z DefaultFormRendereru a len v nej ošetríme konkrétne prípady pre RadioList a Checkbox:class myFormRenderer extends Nette\Forms\Rendering\DefaultFormRenderer public function renderControl(Nette\Forms\IControl $control) { ... $control->setOption('rendered', true); // Is this an instance of a RadioList or Checkbox? if ($control instanceof Nette\Forms\Controls\Checkbox || $control instanceof Nette\Forms\Controls\RadioList) { // Create an empty Html container object $el = Html::el(); // Get all the child items $items = $control->getItems(); // For each child item, add the appropriate control part and label part after one another foreach($items as $key => $item) { $el->addHtml($control->getControlPart($key)); $el->addHtml($control->getLabelPart($key)); } // For all other control types, revert to default functionality } else { $el = $control->getControl(); } ... }Snáď to pomôže každému, kto potrebuje použiteľný
input[type=radio]+labelCSS selektor.
Poďakovanie patrí @Oli, ktorý ma priviedol na správnu stopu.
- ten prvý prípad je pre mňa príliš zložitý, pretože tých checkboxov mám v množstve formulárov veľa. A potrebujem unifikované riešenie, ktoré potrebujem implementovať do viacerých projektov.
 - ten druhý spôsob je pre mňa nepoužiteľný, pretože formulár renderujem nasledovne a pri manuálnom renderovaní sa FormRenderer neuplatňuje:
 
FormControl:
        $form->addCheckbox('fin_soft_saving', $t->trans('project.form.fin_soft_saving'));
        $form->addCheckbox('fin_ematrix', $t->trans('project.form.fin_ematrix'))
            ->setRequired(false);
Výsledok:
<div class="row">
                    <div class="col-md-3">
                        <label for="frm-form-form-fin_soft_saving"><input name="fin_soft_saving" id="frm-form-form-fin_soft_saving" type="checkbox">Soft saving?</label>
                        <span class="form-error-message"></span>
                    </div>
                    <div class="col-md-3">
                        <label for="frm-form-form-is_checked_by_CD"><input name="is_checked_by_CD" id="frm-form-form-is_checked_by_CD" type="checkbox">Overené CD?</label>
                        <span class="form-error-message"></span>
                    </div>
                    <div class="col-md-3">
                        <label for="frm-form-form-fin_ematrix"><input name="fin_ematrix" id="frm-form-form-fin_ematrix" type="checkbox">E-matica?</label>
                        <span class="form-error-message"></span>
                    </div>
                </div>
				
- jurajkovac
 - Člen | 2
 
steelbull napsal(a):
2. ten druhý spôsob je pre mňa nepoužiteľný, pretože formulár renderujem nasledovne a pri manuálnom renderovaní sa FormRenderer neuplatňuje:
A ako vyzerá kód v Latte?