Toggle prvku formuláře – jak skrýt label i control najednou?

m.brecher
Generous Backer | 717
+
0
-

Ahoj,

Potřebuje ve formuláři Nette řídit změnou hodnoty selectu vykreslení/skrytí několika jiných prvků.

Podle dokumentace se použije metoda toggle():
https://doc.nette.org/…s/validation#…

Napsal jsem podle dokumentace takovýto kód formuláře:

        $form->addSelect('type', 'Typ', $typeItems)
            ->addCondition($form::EQUAL, 'ArticleType')
            ->toggle('frm-nodeForm-article_id');	// použito automaticky generované htmlId

            $form->addSelect('article_id', 'Článek', $articleItems);

Formulář vykresluji defaultním rendererem, toggle ale skryje jenom část vykresleného html:

<tr class="required">
	<td class="label">
		<label for="frm-nodeForm-article_id" class="required">Článek:</label> <!-- zůstane vidět -->
	</td>

	<td class="control"> <!-- td zůstane vidět (padding) -->
		<select name="article_id" id="frm-nodeForm-article_id" .....> <!-- skryje se -->
			.....
		</select>
		<span class="required-mark">**</span> <!-- zůstane vidět -->
	</td>
</tr>

Sice se skryje prvek select, ale ve stránce zůstanou zobrazené prvky tr, td, label a span.required-mark. Takže tento způsob dle dokumentace není bohužel prakticky použitelný. Potřebuji, aby se skryl celý řádek tr ideálně css styly display:none.

Napadlo mě jí cestou označit si řádek tr vlastním htmlId (nette id automaticky nepřiděluje) a skrývat pomocí toggle() tento řádek, ale nepřišel jsem na to, jak htmlId řádku tr nastavit (chci použít defaultní renderer formuláře, ne vlastní šablonu).

Další možností je napsat si vlastní metodu toggle pro NetteForms.js.

Řešil někdo podobnou situaci a může poradit nějaké kvalitní řešení?

Editoval m.brecher (4. 9. 2022 16:48)

m.brecher
Generous Backer | 717
+
0
-

Ahoj,

abych pomocí metody toggle() formulářového prvku skryl/zobrazil jak label tak control formulářového prvku, přepsal jsem metodu toggle Nette javascriptu pro formuláře:

    <script>
        Nette.toggle = (selector, visible, srcElement, event) => {
            document.querySelectorAll(selector).forEach((el) => {
                let tr = el;
                while(tr.nodeName !== '#document'){
                    if(tr.nodeName === 'TR'){
                        el = tr;
                        break;
                    }
                    tr = tr.parentNode;
                }
                visible ? el.classList.remove('none') : el.classList.add('none');
            });
        };
    </script>

<style>
	.none { display:none; }
</style>

Javascript funguje pokud vykreslujeme formulář do html tabulky:

<tr>
	<td class="label">
		<label>Typ:</label>
	</td>
	<td class="control">
		<select name="type">.....</select>
	</td>
</tr>

Formulář:

$form->addSelect('type', 'Typ', $this->nodeModel->getTypeItems())
    ->addCondition($form::EQUAL, 'ArticleType')
    ->toggle("[name=type]");

Takže toto řešení je celkem uspokojivé. Při použití selektoru „[name=type]“ pro metodu toggle() je naprosto bezproblémové.

Editoval m.brecher (5. 9. 2022 0:51)

mystik
Člen | 284
+
+2
-

Chyba je v parametru predavanem do toggle. Je potreba se odkazovat na nejake vlastni id/class ne na id samotneho inputu.

Vlastni id obaloveho prvku pro default renderer jde nastavit pomoci setOption('id', 'myId')

m.brecher
Generous Backer | 717
+
0
-

@mystik

Díky moc, tohle přesně jsem potřeboval :).

Hledal jsem něco takového v dokumentaci, ale neuspěl. Tvoje řešení funguje a je jednoduché.

V dokumentaci je specifikace BaseControl::setOption() zde:

https://doc.nette.org/…ms/rendering#…

a zde:

https://api.nette.org/…Control.html#…

Z dokumentace jsem se dozvěděl:

  • BaseControl::setOption() Sets user-specific option
  • setOption(‚description‘, ‚text…‘) vykreslí za pole popisku

Vůbec mě nenapadlo zkusit zadat jako první parametr ‚id‘, protože jsem defaultně předpokládal, že se option týká pouze toho prvku BaseControl. Teď jsem pokusně vyzkoušel $formControl->setOption(‚class‘, ‚my-class‘) a toto také funguje – přidá css třídu obalovému kontejneru prvku.

Závěrem:

Formulář:

$form->addText(....)
	->setOption('class', 'my-class')
	->setOption('id', 'my-id')
	->setOption('description', 'moje popiska');

HTML výstup formuláře:

<tr class="my-class" id="my-id">
	<td class="label">
		<label>Typ:</label>
	</td>
	<td class="control">
		<input type="text" .....><small>moje popiska</small>
	</td>
</tr>