Super továrnička + widget + editační formulář

- Patrik Votoček
 - Člen | 2221
 
Nevíte někdo jak elegantně zkombinovat novou super továrníčku, widget a editační formulář. Už jsem zde psal že předělávám celou appsku na novou super továrničku a widget ale mám jeden problém. Jak na editační formulář?
Do teď:
class MyPresenter extends BasePresenter
{
	public function actionEdit($id)
	{
		$form = new AppForm($this, 'editForm');
		$form->addText('value', "Value: ");
		$form->addSubmit('sub', "Save");
		$form->onSubmit[] = array($this, 'editFormSubmitted');
		$model = new Model();
		$data = $model->getById($id);
		$form->setValues($data); //zjednodušeně
		$this->template->form = $form;
	}
}
{!$form}
S příchodem Super Továrničky se snažím všechno předělat do
createComponentEditForm($name); a v šabloně používat
{control editForm}. Ale je tu problém jak dostat do
formuláře aktuální data? Protože metodě
createComponentEditForm($name); nemám jak předat id
editovaného prvku nebo data. Jediné řešení které mě zatím
napadlo je nepoužívat widget a dělat to takto:
class MyPresenter extends BasePresenter
{
	public function createComponentEditForm($name)
	{
		$form = new AppForm($this, $name);
		$form->addText('value', "Value: ");
		$form->addSubmit('sub', "Save");
		$form->onSubmit[] = array($this, 'editFormSubmitted');
	}
	public function actionEdit($id)
	{
		$form = $this->getComponent('editForm');
		$model = new Model();
		$data = $model->getById($id);
		$form->setValues($data); //zjednodušeně
		$this->template->form = $form;
	}
}
{!form}
A tak se ptám jde tohle něják řešit abych mohl
i u editačního formuláře používat
{control editForm}?

- Ondřej Brejla
 - Člen | 746
 
Já normálně používám {control form}, tobě to hází nějaké chyby či co?
Můj kód vypadá nějak takto:
protected function createComponentForm($name) {
        $form = new MyAppForm($this, $name);
        $form->add...;
        $form->addSubmit('insert', 'Vložit');
    }
public function actionEdit($id) {
        $form = $this->getComponent('form');
        $smth = $this->model->getSmth($id);
        $form->setDefaults(array(
            ...
        ));
        $form->onSubmit[] = array($this, 'editFormSubmitted');
        $this->setView('form');
    }
A normálně funguju…(setView() používám, protože používám jeden form pro edit i insert…)

- Patrik Votoček
 - Člen | 2221
 
Tak to je super jestli to funguje i s naplněním dat. Mě se nepozdávalo
to $form = $this->getComponent('form'); v action. (Nebyl jsem
si jist jestli dojde k naplnění dat v action když volám widget. díky
Editoval vrtak-cz (9. 8. 2009 14:53)

- vlki
 - Člen | 218
 
Myslím, že to byl PetrP, u kterého jsem to v nějakém příspěvku
viděl. Pokud je potřeba pro vytvoření komponenty nějaký parametr, nebát
se použít metodu getParam. Osobně mi to přijde i tak nějak
čistější.
class MyPresenter extends BasePresenter
{
        public function createComponentEditForm($name)
        {
                $form = new AppForm($this, $name);
                $form->addText('value', "Value: ");
                $form->addSubmit('sub', "Save");
                $model = new Model();
                $data = $model->getById($this->getParam('id'));
                $form->setValues($data); //zjednodušeně
                $form->onSubmit[] = array($this, 'editFormSubmitted');
        }
        public function actionEdit($id)
        {
        }
}
vrtak-cz napsal(a):
Tak to je super jestli to funguje i s naplněním dat. Mě se nepozdávalo to
$form = $this->getComponent('form');v action. (Nebyl jsem si jist jestly dojde k naplnění dat v action když volám widget. díky
Dojde, protože si aplikace projde tou action částí. Pokud bys tam akcí
ale měl víc a v některé bys v rámci následného view použil
{control editForm}, tak by ses pak mohl divit.

- David Grudl
 - Nette Core | 8285
 
Vyčlenit naplnění dat do metody actionEdit je určitě správný
přístup. I tak můžeš použít v šabloně
{control editForm}. Takže actionEdit může vypadat i takto:
       public function actionEdit($id)
        {
                $model = new Model();
                $data = $model->getById($id);
                $this['editForm']->setDefaults($data);
        }
				
- Sqdw
 - Člen | 3
 
Zkoušel jsem použít Davidovu verzi a obávám se, že to úplně nešlape.
Widget se zobrazí jedině pokud v metodě createComponentMyForm
použiju return $form, jenže i když potom použiju metodu
setDefaults, tak formulář se pochopitelně zobrazí prázný…
Dá se to vyřešit nějak jinak, abych mohl použít
{control myForm} ?
Editoval Sqdw (11. 1. 2010 15:48)

- setka
 - Člen | 10
 
V souvislosti s tímhle bych se chtěl zeptat na jednu věc:
Vyčlenit naplnění dat do metody actionEdit je určitě správný přístup. I tak můžeš použít v šabloně {control editForm}. Takže actionEdit může vypadat i takto…
Co jsem zkoušel, tak Action se volá ještě před obsluhou signálů, a to i signálů z komponent. Dejme tomu, že mám ve stránce např. komponentu – anketu. Hlasování v anketě je řešeno jako signál, potud vše funguje výborně.
Navíc ale hlasování v anketě realizuji AJAXem (používám jQuery řešení v podstatě totožné s tím přímo z Nette, nepoužívám mechanismus snippetů – obsluha signálu nastaví payload a volá terminate()) – jako asynchronní request na signál té komponety. V tomto případě se úplně zbytečně v Action volá model (třeba načtení dat z databáze), který třeba plní nějaký formulář ve stránce.
Napadlo mě plnit formulář daty z modelu až v Render metodě, mohou s tím být nějaké problémy? Pak mi z toho ale vychází, že Action bych využíval jen a pouze na případné přesměrování.

- Sqdw
 - Člen | 3
 
Ondřej Mirtes napsal(a):
Sqdw: Ukaž kód, mělo by to rozhodně fungovat.
<?php
protected function createComponentArticleEditForm()
{
	$form = new AppForm;
	...
	return $form;
}
public function actionEdit($articleId) {
	$article = ArticleManager::getArticle($articleId);
	$this['articleEditForm']->setDefaults(get_object_vars($article));
}
?>
A v šabloně potom:
{control articleEditForm}
Když dám Debug::dump($this['articleEditForm']); v
actionEdit, tak tam ty data jsou, ve widgetu se nezobrazí, raději
se ale ještě mrknu, jestli nemám starou verzi Nette…

- Ondřej Mirtes
 - Člen | 1536
 
A vrací ten konstrukt get_object_vars($article) pole, jaké
metoda setDefaults požaduje?

- MzK
 - Člen | 127
 
Mám trochu podobný problém.. V šabloně mám
<h2>$article-name</h2>... atd.{control form1}
A do toho widgetu chci použít parametr $article->id aby se
komentář vložil ke správnému článku.
{control form1($article->id)} nejde,
ani {control form1 $article->id}..
řešení
nechci používat → zbytečný SQL dotaz pro ID článku, když už jednou
proběhl pro výpis článků.
Ostatně stejný parametr jsem již v té samé šabloně použil pro výpis
článků takto:
{foreach $presenter->getComments($article->id) as $comment}
<p>{$comment->text}</p>
{/foreach}
Jak tedy použít u továrničky parametr ze šablony?
Editoval zacatecnik (20. 1. 2010 12:52)

- Ondřej Mirtes
 - Člen | 1536
 
Vytáhni si to ID v odesílací metodě formuláře přes $this->getParam(‚id‘) (kde id je název parametru z nějaké renderArticle metody) a pracuj s ním tam – předávat ho formuláři při renderování je pozdě…

- Ondřej Mirtes
 - Člen | 1536
 
Tak si to pak podle toho vyhledej přes dva dotazy :) A pokud ten dotaz v Presenteru už provádíš, tak ho přesunň do action* (protože v render* bylo už pozdě a odesílací metoda by o něm nevěděla) a nacachuj si ho do vlastnosti objektu, ať ho nemusíš provádět dvakrát. Nebo to nech na starost modelu…

- MzK
 - Člen | 127
 
Už jsem to udělal takto:
<?php
public function renderArticle($url) { // vypise jeden clanek.
	$model = new ArticlesModel;
	$data = $this->template->article = $model->getArticle($url);
	**$this->text_id = (int) $data['id'];** //timto ulozim do tridy
}
?>
A pak ve createComponentForm1 jenom dam
->value = $this->text_id;
Funguje to. Ale ptám se, e na tomto přístupu něco špatně?
Editoval zacatecnik (20. 1. 2010 16:10)

- Ondřej Mirtes
 - Člen | 1536
 
Je to špatně – protože může nastat situace, kdy se ti komponenta
vytvoří dřív než nastane renderArticle fáze a $this->text_id budeš
mít prázdné. Proto bych to přesunul do
actionArticle($url);.