Vynechání prvku z vykreslování formuláře

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

Prosím, jak vynechám při renderu jeden prvek formuláře? Zkoušel jsem ho vynechat za pomocí fce, která je popsána v tutoriálu, ale nechce mi to fungovat. Nějaký fígl?

$form['save']->setRendered(TRUE);

mi stále zobrazuje prvek s názvem ‚Save‘ :-/

Nette: 2.0

Mikulas Dite
Člen | 756
+
0
-

Jestli setRendered, tak:

$form['save']->setRendered(FALSE);
chemikus
Člen | 49
+
0
-

Ať použiju TRUE a nebo FALSE, tak se mi prvek stále zobrazuje (a to ho volám přímo v komponentě, kde nastavuji formulář) :-/ A ještě taková perlička. Normálně bych ten prvek chtěl nechat vykreslovat (při vkládání záznamu) ale při jeho editace ho nezobrazovat. Proto při editacei záznamu volám funkci

public function editaceAkce() {
	$form = $this->getComponent('akce');
	$form["save"]->setRenderer(TRUE);
}

Jo a abych byl ještě přesnější, jedná o prvek, ve kterém připojuji fotografie (soubory)

Editoval chemikus (30. 10. 2010 13:41)

Mikulas Dite
Člen | 756
+
0
-

Chápu. Problém je tady docela jasný: funkce editaceAkce() nic nedělá. Formulář se vždy vezme z createComponentAkce(). Nejsnažší (ale ne nejlepší) je vytvořit formulář pro tvorbu createComponentAkce() a poté v createComponentAkceEdit() vytvořit nový, třeba takhle:

createComponentAkceEdit()
{
	$form = $this->getComponent('akce');
        $form["save"]->setRendered(FALSE);
	return $form;
}

Mimochodem setRenderer a setRendered jsou úplně jiné věci.

Editoval Mikulas Dite (30. 10. 2010 13:45)

chemikus
Člen | 49
+
0
-

Hmm… výsledek stále stejný. Tak znovu více popíšu:

protected function createComponentAkce() {
	$form = new NAppForm;

	$form->addGroup("Informace o akci");
	$form->addText("nazev", "Název: ", "45");
	$form["nazev"]->setRendered(TRUE);
	//$form["nazev"]->setRendered(FALSE);

	$form->addSubmit('odeslat', 'Přidat');
	$form->onSubmit[] = array($this, 'akceSubmitted');

	return $form;
}

Ale stále se mi vykresluje prvek „nazev“. A to ho nechávám ovlivnit nijak další funkcí co se týče editace nebo tak :-)

A nerad bych vytvářel další komponentu pro editaci a rád bych elegantně schoval možnost přidávání fotografie. Ovšem, komponentu bych tam mohl zanechat, ale již to mám vymyšlené zcela jinak.

Mikulas Dite
Člen | 756
+
0
-

Tak jednak Form má fluent interface, takže místo

$form->addText("nazev", "Název: ", "45");
$form["nazev"]->setRendered(FALSE);

se píše

$form->addText("nazev", "Název: ", "45")
	->setRendered(FALSE);

Každopádně jsem do kouknul do api a rozhodně jsem tam setRendered neviděl. Bavíme se o verzi 2?

Schovávat nějaké políčko ve formuláři takhle bych nezařadil mezi best practice. Teoreticky by šlo formulář tvořit takhle:

$form = AppForm;
//...
if ($this->action == 'akce') {
	$form->addText(/*...*/);
}
if ($this->action == 'edit') {

}
return $form;

Imho se ale v první řadě snažíš něco obcházet/řešit jinou než Nette cestou.

Edit: a nemíchej prosím české a anglické názvy ; ) hrozně špatně se to potom čte.

Editoval Mikulas Dite (30. 10. 2010 14:32)

Solution
Člen | 50
+
0
-

Zdravím,

zkoušel jsem to také, verze 2 pro 5.2 s prefixy.
Projel jsem conventionalrender(třída pro vykreslování formů), našel jsem v ní toto:

<?php
	foreach ($this->form->getGroups() as $group) {
	if (!$group->getControls() || !$group->getOption('visual')) continue;
// V metodě renderBody()
?>

tznm., že když nějakému prvku nastavíte setRendered nebo přes setOption hodnotu visual na true, tak by
se ta komponenta neměla vykreslit, bohužel se tak děje při obouch stavech, nevím proč.
Že by chyba? Nebo jsem to jen špatně pochopil?
Zkouším to na tomto:

<?php
        $ff = new NForm();
        $ff->addButton('Ahoj','caac')->setOption('visual',true);
?>

Editoval Padik (30. 10. 2010 14:36)

Mikulas Dite
Člen | 756
+
0
-

Padik napsal(a):
// V metodě renderBody()

To se ale vztahuje na $group, ne na jednotlivé prvky.

Edit:

$form->addGroup()
	->setOption('visual', TRUE);
$form->addCheckbox('checkbox');

by checkbox orámovalo, s FALSE ne.

Editoval Mikulas Dite (30. 10. 2010 14:41)

Solution
Člen | 50
+
0
-

V tom případě metoda setRendered je špatně, jelikož na group se nevztahuje a když nastavím group, setOption(‚visual‘,true);, tak se akorát nevykreslí rámec okolo prvků jinak tam prvky stále jsou.

Vyki
Člen | 388
+
0
-

Nevím jestli jsem dobře pochopil co je konkrétním záměrem, ale dalo by se to udělat např takto:

<?php
//vykresluje formulář pro 2 view - 1) view přidat akci
				 - 2) view editovat akci

//definice komponenty
protected function createComponentNewsform()
{
	$form = new AppForm();

        $form->addHidden('id');

        $form->addText('name', 'Název akce')
             ->addRule(Form::FILLED, 'Vyplňte prosím název akce');

        $form->addSubmit('savenews', 'Uložit a publikovat')
             ->onClick[] = callback($this, 'newsClicked');
}

//definice view 1)

public function renderDefault()
{
	unset($this['newsform']['id']); //zde odstraním hidden field id, vkládám nový záznam, kde id není známo
}

//definice view 2)
public function renderEdit($id)
{
	$data = NewsModel::findById($id)

	$this['newsform']->setDefaults(array(
           'id' => $data['id'],
	   'name' => $data['name']
	));
}

//definice obsluzne metody
public function newsClicked(SubmitButton $button)
{
	$data = $button->getForm()->getValues();

	if(isset($data['id']))
	{
		NewsModel::update($data);
	} else {
		NewsModel::add($data);
	}
}
?>
Mikulas Dite
Člen | 756
+
0
-

Padik napsal(a):

V tom případě metoda setRendered je špatně, jelikož na group se nevztahuje.

Právě že správně je, vztahuje se jenom na group.

Viki napsal(a):

Takhle bych to radši nedělal, unset mi tam nepříde košer.

Řešení jsou:

  • nejlepší je mít pro edit vlastní formulář
  • edit formulář odvozený od původního
  • mít jednu továrničku a měnit jí podle akce
  • a pak další, které obchází logiku stávajících Nette formulářů
Solution
Člen | 50
+
0
-

Na group se vztahuje:

<?php
$form->addGroup()->setOption('visual',true); //To ale ovlivnuje vykreslení rámce
?>

na group se setRenderer() nedá aplikovat, ten se dá aplikovat na jednotlivé prvky, viz:

David Grudl
>Zavoláním $form[‚save‘]->setRendered(TRUE) je vynecháte z vykreslování $form->render(‚body‘) a pak je můžete vykreslit ručně.

čili:

<?php
$form->addButton('test','test')->setRendered(true); //Prvek se nemá vykreslit samovolně, pokud se používá conventional render
?>

Takže metoda setRendered() neplní svou fci.

Editoval Padik (30. 10. 2010 17:40)

Vyki
Člen | 388
+
0
-

Mikulas Dite napsal(a):
Takhle bych to radši nedělal, unset mi tam nepříde košer.

Zajímal by mě argument proč to není „košer“. Je to operace na úrovni FormContaineru, jednoduše odeberu jednu položku. Vídíš tam snad nějakou bezpečnostní hrozbu, pokud ano, kde?

Řešení jsou:

  • nejlepší je mít pro edit vlastní formulář

To mi rozhodně „nejlepší“ nepřijde. Psát kvůli přidání jedné položky do FormContaineru novou továrničku je v celku zbytečné.

Editoval Vyki (30. 10. 2010 21:21)

Filip Procházka
Moderator | 4668
+
0
-

AppForm::render() → Form::renderBegin() – automaticky vyresetuje všechny prvky na rendered FALSE, proto to jde použít jedině v templatě

Skrývání komponent formuláře je prasárnička, udělal bych to nějak takhle :)

private function createMyFormBase($name)
{
	$form = new AppForm($this, $name);

	$form->adddText('...', ...);
	// ...

	return $form;
}


public function createComponentMyFormNew($name)
{
	$form = $this->createMyFormBase($name);

	$form->addSubmit('new', 'Uložit');
	$form->onSubmit[] = callback($this, 'saveNew');

	return $form;
}


public function createComponentMyFormEdit($name)
{
	$form = $this->createMyFormBase($name);

	$form->addHidden('id', $this->getParam('editId'));
	$form->addSubmit('edit', 'Uložit');
	$form->onSubmit[] = callback($this, 'saveEdit');

	return $form;
}

Editoval HosipLan (1. 11. 2010 8:58)

westrem
Člen | 398
+
0
-

Chemikus by mohol aspon uviest aku verziu Nette pouziva.

V pripade 0.9.* musi setOption('rendered', TRUE) fungovat, v preklade to znamena, ze mu akoby dopredu nastavis, ze uz bol vyrendrovany a teda sa ma preskocit (vid API ), (nechapem tak trochu zmetky s nastavovani na false alebo true :-/ )

V pripade 2.0 aspon podla aktualnej API to musi fungovat tak isto. Nove formulare (ktore uz mali byt commitnute ale nie su), riesia rendering uplne odlisne.

Posli prosim teda viac kodu, aj sablonu napriklad, pretoze to jednoducho fungovat musi.

Co sa tyka setOption('visual', TRUE) – sposobi, ze sa nevykreslia prvky danej grupy – teda grupa samotna, jednoducho sa preskoci v iteracii.

Mikulas Dite napsal:
Takhle bych to radši nedělal, unset mi tam nepříde košer.

Praveze to koser uplne je – je to regulerne odstranenie prvky z formularu, nie je na tom nic zle. To unset je v tomto pripade skratka pre removeComponent kde pri formulare by si musel predavat na odstranenie samotnu komponentu a nie len nazov, preto unset ako the faster way.

nejlepší je mít pro edit vlastní formulář

Suhlasim s Vyki – toto je imho zla varianta, duplicita kodu, kvoli jednej polozke? Fakt ee ..

Najlepsie riesenie je imho mat tovarnicku, ktora vytvori zakladny skeleton – kostru formularu a potom v patricnych akciach doplnat (vynimocne odoberat) prvky podla potreby.

Mikulas Dite
Člen | 756
+
0
-

Vyki napsal(a):

Zajímal by mě argument proč to není „košer“. Je to operace na úrovni FormContaineru, jednoduše odeberu jednu položku. Vídíš tam snad nějakou bezpečnostní hrozbu, pokud ano, kde?

Asi ani ne tak bezpečnostní problém, jako spíš teoretický. Je mi bližší něco opatrně tvořit, než to naskládat v továrničce a poté odebírat. Souhlasím s tebou, že unset nad containerem dokonce ani nemůže zapříčinit nějaký problém.

Podmínka v továrničce je lepší, než úprava formuláře v render (nemluvím o setDefualts a vzhledu) – všechny komponenty formuláře jsou tam na jednom místě. Osobně bych nechtěl projíždět všechny rendery a hledat, proč se zrovna tady něco nevykreslilo.

Každopádně to tvé řešení je plně funkční a správné : ) Já sám mám radši (i delší) kód nad kterým se neztratím i po delší době.


Chemikus psal hned v prvním postu Nette 2.0, předpokládám tedy nějaký nový build? V downloadech je 14. 10. 2010, což sedí.