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

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

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
+
0
-

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
+
0
-

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
+
0
-

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.

PetrP
Člen | 587
+
0
-

vlki napsal(a):

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ší.

Haha, zrovna jsem to sem šel napsat ;]

David Grudl
Nette Core | 8105
+
0
-

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
+
0
-

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)

Ondřej Mirtes
Člen | 1536
+
0
-

Sqdw: Ukaž kód, mělo by to rozhodně fungovat.

setka
Člen | 10
+
0
-

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
+
0
-

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
+
0
-

A vrací ten konstrukt get_object_vars($article) pole, jaké metoda setDefaults požaduje?

Sqdw
Člen | 3
+
0
-

Ondřej Mirtes napsal(a):

A vrací ten konstrukt get_object_vars($article) pole, jaké metoda setDefaults požaduje?

Jj, to bylo dobře… už je to OK, omlouvám se, asi jsem se někde přehlédl, funguje to správně.

MzK
Člen | 127
+
0
-

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
+
0
-

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ě…

MzK
Člen | 127
+
0
-

To asi nepůjde, protože článek hledám dle nejaky-clanek-url, ale komentáře pod $id_clanku a tak mi getParam() vrati toto:

<?php
array(2) {
   "action" => string(7) "article"
   "url" => string(13) "nazev-clanku"
}
?>
Ondřej Mirtes
Člen | 1536
+
0
-

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
+
0
-

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
+
0
-

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);.