render komponenty (formuláře) podle dat z jiného formuláře

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

Zdravím, rád bych se zeptal na následující problém:
Mám dva formuláře –

FORMULÁŘE

Class FormTwo extends Nette\Application\UI\Form{

   protected $typ = null;

   public function __construct(\Nette\ComponentModel\IContainer $parent = NULL, $name = NULL){
		parent::__construct($parent,$name);
   }
   public function setFormType($type){
   $this->typ = $type;
  }

   public function buildForm(){
   if($this->typ=='form_type_one') $this->addText('label','Label');
   if($this->typ=='form_type_two') $this->addText('other_label','Other label');
   }
   public function render(){
        $this->buildForm();
        parent::render();
   }

}

PRESENTER:

public function createComponentFormOne(){
$form = new FormOne();
return $form;
}
public function createComponentFormTwo(){
$form = new FormTwo();
return $form;
}

mám metodu formOneSubmitted:

public function formOneSubmitted($form){
$data = $form->getValues();
if($data['select']=='form_type_one') $this['formTwo']->setFormType($data['select']);
}

PROBLÉM:
problém je v sestavení formTwo. Jelikož potřebuju komponentě nastavit různé parametry v závislosti na prvním formuláři (formOne), sestavuji jednotlivé prvky až v render metodě formTwo. Ale při odeslání formuláře formTwo je zapotřebí, aby byly prvky sestaveny ještě před render metodou (jinak následuje error: Component with name ‚label‘ does not exist.)
Problém je tedy v tom, kdy sestavit jednotlivé prvky druhého formuláře, aby je bylo možné ovlivnit daty z prvního formuláře?
Díky za případné odpovědi

Editoval drakul (12. 12. 2011 0:37)

klip
Člen | 11
+
0
-

Možná hloupej dotaz, ale navázal si callback na formOneSubmitted k onSuccess toho prvního formu?

<?php
public function createComponentFormOne()
{
	$form = new FormOne();
	$form->onSuccess[] = callback($this, 'formOneSubmitted');
	return $form;
}
?>

V ukázce to nevidím.
Případně jestli máš víc tlačítek, tak na onClick[] k tomu tlačítku (viz https://doc.nette.org/cs/forms#… ).

S Nette si hraju teprve pár dní, ale podle mě by to mělo normálně fungovat.
Podle selskýho rozumu, rychlého pohledu do kódu Nette a i podle zkoušky vypsání callbacku z jedné metody obsluhující formulář se volají nejdříve callback metody a pak teprve se volá render :)

Filip Procházka
Moderator | 4668
+
0
-

To ti nemůže fungovat :) Hned z několika důvodů.

  • Formulářové prvky přidáváš až v render – pozdě.
  • Spoléháš, že odesláním jednoho formuláře upravíš druhý, ale to nejde. Nette formuláře totiž používají ke svému „odeslání“ signál (ano takovéto handle) a jak jistě víš, signál může být jenom jeden v daném requestu. Takže jeden by se ti odeslal, druhý by se správně vykreslil, ale až bys chtěl odeslat ten druhý, nevytvořily by se žádné inputy a formulář by nic nepřijal.

Napadají mě dvě cesty. 1) Využít session

private $formTwoType;


protected function startup()
{
	parent::startup();

	$this->formTwoType =& $this->getSession('formTwo')->type;
}

protected function createComponentFormOne()
{
	$form = new FormOne();
	$form->onSuccess[] = callback($this, 'FormOneSubmittedChangeFormTwoType');
	return $form;
}

public function FormOneSubmittedChangeFormTwoType($form)
{
	$this->formTwoType = $form->values['select'];
}


protected function createComponentFormTwo()
{
	if ($this->formTwoType === 'one') {
		$form = new FormTwoFirstVariant();

	} else {
		$form = new FormTwoSecondVariant();
	}
	return $form;
}

Určitě chápeš, kam tím mířím :)

Varianta číslo 2: Znáš toggle? Validační pravidla formulářů mají jednu šikovnou metodu, vygeneruje vedle validačních pravidel „schovávací pravidla“ a nette.forms.js se o to pak postará. Samozřejmě Javascripty-only.

$form = new Form();
$foo = $form->addSelect('foo', 'Foo', array(1 => 'Lister', 2 => 'Rimmer'));
$bar = $form->addText('bar', 'Bar');

$s->addCondition(Form::EQUALS, 1)->toggle($bar->getHtmlId());

Nyní, když vebereš Listera, tak by se „Bar“ měl zobrazit a když vebereš Rimmera tak se schová :)

PS: Chválím použití formulářů jako samostatné třídy!

drakul
Člen | 37
+
0
-

Zdravím, děkuji moc za odpovědi.

Metoda se SESSION mě také napadla, přišla mi „příliš komplikovaná“. Vytvářet session jen pro uložení hodnoty z jednoho formuláře, který se de-facto použije jen jednou … to mi přišlo neefektivní.

Řešení s toggle jsem původně zamítl z toho důvodu, že potřebuji mít ve formuláři element „Name“.

Ten je v prvním případě (form-type-one) typu input-text.

V druhém se jedná o Container (který obsahuje dva elementy input-text).

Po odeslání se zjišťuje, zda-li je hodnota v „Name“ typu array(). Pokud ano, zpracuje se pomocí join() na string.

PS: Mám ještě jeden problém s toggle. Pokud jej navážu na element „$bar“ v příkladu od HosipLana, schová se mi pouze input box, ale ne label před ním.

Filip Procházka
Moderator | 4668
+
0
-

S těmi toggle máš pravdu, koukni sem

Co se týče session, neuraž se, ale řeknu ti to takhle: jsi paranoidní :)