Událost onSuccess se nezavolá
- Nutelac
- Člen | 58
Vytvářím si komponentu stepControl, která se bude starat o vícekrokový
formulář. V jednom momentě potřebuji v komponentě (stepControl) přidat
formuláři událost onSuccess, která mi zajistí přesměrování na další
formulář. Událost se přidá (zjištěno pomocí
dump($form->onSuccess)
), ale nezavolá se. V presenteru ale
vše funguje.
Událost přidávám takto:
$form->onSuccess[] = function($form) use ($step){
$this->presenter->redirect('this', array('step' => $step));
$stop(); //nezavolá se
};
Editoval Nutelac (10. 11. 2012 11:46)
- vvoody
- Člen | 910
Potom nieje dôležitá definícia callbacku ale skorej to kde ho definuješ. Ukáž viac kódu. V tvojom prípade zrejme nieje callback ešte uložený v onSuccess v momente kedy sa spracúvajú signály. Podobný problém
- Nutelac
- Člen | 58
Už jsme přišel na příčinu, ale nevím jak ji řešit. Vícekrokový formulář tvořím tak, že pro každý krok si vytvořím formulář v presenteru, který poté předávám do komponenty StepControl. Problém nastane při vytváření formuláře, konkrétně v metodě Form::fireEvents(), která se zavolá ještě předtím, než odešlu formulář do komponenty StepControl a která se stará o událost onSuccess, takže už není možné přidávat další události. Je to možné nějak vyřešit, nebo vás napadá úplně jiný způsob jak řešit přesměrování na další krok?
- Nutelac
- Člen | 58
vvoody napsal(a):
public function createComponentStep1()
{
$form = new Form;
$form->addText('email');
$form->addSubmit('submit');
return $form;
}
public function createComponentStep2()
{
$form = new Form;
$form->addText('name');
$form->addSubmit('submit');
return $form;
}
public function createComponentStepForm()
{
$form = new StepControl; //unitř StepControlu nastavuji onSuccess
$form->addStep($this['step1']);
$form->addStep($this['step2']);
return $form;
}
- vvoody
- Člen | 910
Ukáž celý StepControl. Továrnička pre tie dva formuláre by mala byt logicky v tej komponente, čim sa korektne naviažu na komponentovú štruktúru (alebo ako to mam nazvať) Nette. Neviem čo s tými formulármi robíš v metóde addStep, preto si chcem pozrieť kód tej komponenty. Keď odošleš niektorý z tých formulárov, aká url adresa je v prehliadači?
- Nutelac
- Člen | 58
url: /?stepForm-step=step1&do=step1-submit
class StepConrol extends Control
{
/** @persistent */
public $step;
private $steps;
public function render()
{
$this->template->setFile(__DIR__ . '/StepControl.latte');
$this->template->step = $this->getStep($this->step);
$this->template->render();
}
public function addStep(IContainer $step)
{
$this->steps[$step->name] = $step;
}
public function getStep($name)
{
$step = $this->steps[$name];
$next = 'step2';
$step->onSuccess[] = function() use ($next){
$this->presenter->redirect('this', array('step' => $next));
};
return $step;
}
}
- vvoody
- Člen | 910
No uvedom si to že StepConrol pri spracovaní formuláru nieje vôbec
vytvorený. StepControl je vyžadovaný až počas rendrovania keď voláš
{control StepForm} čiže naviazanie callbackov je vykonané až počas
rendrovania šablóny. Jedna možnosť je zabespečiť aby bol StepConrol
inicializovaný počas inicializácie jednotlivých formulárov.
public function createComponentStep1()
{
$form = new Form;
$form->addText('email');
$form->addSubmit('submit');
$this['stepForm'];
return $form;
}
public function createComponentStep2()
{
$form = new Form;
$form->addText('name');
$form->addSubmit('submit');
$this['stepForm'];
return $form;
}
public function createComponentStepForm()
{
$form = new StepControl; //unitř StepControlu nastavuji onSuccess
$form->addStep($this['step1']);
$form->addStep($this['step2']);
return $form;
}
čo je len škaredý hack, ktorým ti chcem ujasniť prečo ti to
nejde. (edit: Nie radšej to ani neskúšaj :D to by skoncilo zrejme
nekonecnym cyklom.) Druhá a správna (a oveľa logickejšia) možnosť je mať
továrničky formulárov v StepControl. V takomto prípade signál odoslaného
formulára najskorej putuje do StepControl, čím vynúti jeho vytvorenie a až
potom do konkrétneho formuláru.
Editoval vvoody (10. 11. 2012 15:23)
- Nutelac
- Člen | 58
Myslíte to, že bych přesunul vytváření formulářů (metody createComponentStep*) do StepControlu? Něco jako:
public function createComponentStepForm()
{
$form = new StepControl;
$form->addStep('step1')
->addText('email');
$form->addStep('step2')
->addText('name');
return $form;
}
Editoval Nutelac (10. 11. 2012 15:57)
- blacksun
- Člen | 177
Naopak.
<?php
class StepConrol extends Control
{
/** @persistent */
public $step;
private $steps;
public function render()
{
$this->template->setFile(__DIR__ . '/StepControl.latte');
$this->template->step = $this->getStep($this->step);
$this->template->render();
}
public function addStep(IContainer $step)
{
$this->steps[$step->name] = $step;
}
public function getStep($name)
{
$step = $this->steps[$name];
$next = 'step2';
$step->onSuccess[] = function() use ($next){
$this->presenter->redirect('this', array('step' => $next));
};
return $step;
}
public function createComponentStep1()
{
$form = new Form;
$form->addText('email');
$form->addSubmit('submit');
return $form;
}
public function createComponentStep2()
{
$form = new Form;
$form->addText('name');
$form->addSubmit('submit');
return $form;
}
.....
}
?>
- mildabre
- Člen | 62
Nutelac napsal(a):
Vytvářím si komponentu stepControl, která se bude starat o vícekrokový formulář. V jednom momentě potřebuji v komponentě (stepControl) přidat formuláři událost onSuccess, která mi zajistí přesměrování na další formulář. Událost se přidá (zjištěno pomocí
dump($form->onSuccess)
), ale nezavolá se. V presenteru ale vše funguje.Událost přidávám takto:
$form->onSuccess[] = function($form) use ($step){ $this->presenter->redirect('this', array('step' => $step)); $stop(); //nezavolá se };
Projel jsem si celou tu diskusi a napadlo mne, zda je to z analytického hlediska vůbec dobrý nápad si vyrábět obecnou komponentu pro obsluhu vícekrokového formuláře. Nevím přesně jak má takovýto vícekrokový formulář vypadat a jakým způsobem zpracovává data, ale…
Po mnoha pokusech a variantách jsem dospěl k názoru, že složité formuláře uživatelé nemilují a radši vyplňují „vícekrokové“ formuláře kde se soustředí v každém kroku vždy na část problematiky. Otázkou je plná kontrola uživatele nad pohybem na krocích a data se nesmí ztratit. Já to řeším tak, že jednotlivé formuláře jsou nezávislé komponenty a mají tlačítko vpřed a zpět (nebo pokračovat a zpět). Data jednotlivých formulářů se ukládají do objektu v SESSION aby byly přístupné i mezi jednotlivými http requesty. Úplně na konci uživatel obvykle vše potvrdí a následuje uložení dat z objektu v SESSION do databáze. Tlačítko vpřed vykoná uložení dat formuláře a přesměrování na další formulář, tlačítko zpět přesměruje na předchozí formulář.
Má smysl si pro takto jednoduchý koncept vytvářet nějakou stepKomponentu ? Tím si jenom zkomplikuješ život. Ostatní Ti zde radí jak tuto šílenost naprogramovat, ale já radím jít na to jednoduchou a přímou cestou klasickými formuláři. Takovéto všeobalující komponenty IMHO Ti nic nezjednoduší. Ale třeba se mýlím, musel bych znát detaily Tvého formuláře.
- Filip Procházka
- Moderator | 4668
mildabre napsal(a):
Má smysl si pro takto jednoduchý koncept vytvářet nějakou stepKomponentu ? Tím si jenom zkomplikuješ život.
Krokové formuláře dělám přesně jak popisuješ, ale…
Udělat si obecnou komponentu, která se bude starat o ukládání dat z formuláře do session automaticky a která ti bude moct validovat vazby mezi kroky je velice pohodlné.
Problém je, že každá aplikace má svá specifika (jiný způsob procházení tohoto formuláře) a ještě jsem nevymyslel, jaké je ideální api pro takovou komponentu. Vždy ji píši znovu.
Ovšem je to pár řádků a díky tomu že to vyčlením, tak to nemusím psát několikrát v jedné aplikaci ;)