render komponenty (formuláře) podle dat z jiného formuláře
- drakul
- Člen | 37
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
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
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
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
S těmi toggle máš pravdu, koukni sem
Co se týče session, neuraž se, ale řeknu ti to takhle: jsi paranoidní :)