Formulare jako tovarnicky – vlastni vykresleni formulare nefunguje

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

Zdravim,
udelal jsem si tovarnicky dle tohoto navodu:
https://doc.nette.org/…s/form-reuse
jenze kdyz se snazim vyrenderovat form rucne {form newsletterForm} … {/form}

Jenze $form obsahuje instanci NewsletterForm tridy a ne Form, proto nejde vykreslit.

Jak to resite? Delam neco spatne?

Diky za postrceni.

bazo
Člen | 620
+
0
-

vyrob si sablonu pre komponentu a v nej vyrenderuj form rucne. potom v ostatnych sablonach len zavolas {control newsletterForm}

Jan Endel
Člen | 1016
+
0
-

Ukaž jak v presenteru tu komponentu voláš.

Ja
Člen | 260
+
0
-

@bazo : jo dik, to by mohlo fungovat, v tuto chvili ten vlastni render probiha skrze echo $this[‚form‘]; primo v te komponente

@JanEndel :

<?php
protected function createComponentNewsletterForm()
    {
        $form = $this->newsletter_form_factory->create();
        $form->onSuccess[] = function ($form, $status) {
			// vypusteno
        };

        return $form;
    }
?>
Šaman
Člen | 2668
+
+1
-

Ten návod je dobrý, ale osvědčilo se mi důsledně rozlišovat Form, Control a Factory.
Podle názvu by ta tvoje NewsletterForm měla extendovat Form, ale ona je to asi buď komponenta (pak to pojmenuj NewsletterFormControl) a nebo továrna (pak je to NewsletterFormFactory). A pokud by to byla továrna, která vrací komponentu, pak je vhodný, i když dlouhý název NewsletterFormControlFactory.

Vykreslení pomocí makra {form NewsletterForm}…{/form} funguje jen u Formu, komponenta zase lze vykreslit pomocí {control NewsletterFormControl}.


Jinak osvědčilo se mi mít továrny přímo na formuláře. Komponenty vytvářet jen tehdy, pokud stejně naformátovaný formulář budu chtít na více místech. Pokud mu však na backendu jen přiřadím nějaký umiverzální renderer a na frontendy ho vykresluji přímo oživením inputů v dodaných šablonách, pak se lépe pracuje se instancí Form, než FormControl.

Editoval Šaman (3. 3. 2015 22:25)

Ja
Člen | 260
+
0
-

Jj, ok diky, jako je to komponenta, ale je to z toho duvodu, abych si mohl vytvorit svuj vlastni event onSuccess[], abych odchytil, zda se email do newsletter pridal, nebo odebral. Proto je to udelano skrze tento navod. Pokud bych mel jen tovarnu, jako mam u ostatnich formu, tak se mi ten onSuccess[] nedarilo vytvorit a pouzit.

Šaman
Člen | 2668
+
0
-

Tak to děláš něco špatně, onSuccess funguje i mimo komponenty. Asi tuším proč by ti to mohlo dělat problém, ale to nesouvisí s formuláři. Zkus tu továrnu podědit od Nette\Object, nebo ten callback navěšovat pomocí

$form->onSuccess[] = [$this, 'onSubmit'];
Ja
Člen | 260
+
0
-

@Šaman : heled, to onSuccess[] funguje, jen mi nejde nastavit vlastni event. Ted jsem to kratce zkoumal a prave problem je, ze pokud automaticky vytvarim form pres tovarnu, tak se mi vrati ‚Form‘, ale pokud to vytvarim skrze ten interface, tak mi to vraci ‚NewsletterForm‘, diky cemuz se dostanu k tomu svymu event handleru. Takze nejak nevim jak z toho ven.

(kazdopadne co ja vlastne jsem puvodne resil, tak bylo to, abych prave si pri odeslani/zpracovani formulare dokazal v presenteru vytahnout, co se vlastne stalo a adekvatne na to zareagovat hlaskou [email byl smazan/pridan/atd..])

Šaman
Člen | 2668
+
0
-

Jenomže jestli to správně chápu, tak NewsletterForm není instance Form.
Nevím s čím máš problém a o jakých eventech vlastně mluvíš. Jestli třeba Kdyby\Events, tak ty zatím nepoužívám a nedokážu poradit. Ale na normální navěšování událostí na onSubmit kdekoliv (v továrně, komponentě i presenteru) nepotřebuješ, aby ten Form byla komponenta.
(Komponenta je fajn, když potřebuješ komponentu, ale když chceš jen Form, tak je to zbytečné obalování které může přinést problémy.)
Ukázku máš tady: Tovární třída na čistý formulář a její použití v presenteru i s další navěšenou událostí.

(Jen upozorňuji, že tahle továrna dědí od Nette\Object, jinak by nefungoval ten zápis kde se navěšuje událost na onSuccess. V čistém PHP by bylo potřeba použít pole.
A taky těmi traity se asi neispiruj, dneska už je nepoužívám, zvytečně znepřehledňují kód. Takže na aktuálních projektech si úplně obyčejně tu továrnu injectnu.)

Ja
Člen | 260
+
0
-

@Šaman : jj, chapes to spravne
ad. eventy – jj eventy = udalosti, nemyslim kdyby/events.. myslim tim treba napr. onSuccess[], jenze ja do toho onSuccess[] (nebo jineho vlastniho eventu) potrebuju dostat informaci, co se s emailem stalo a nechat to probublat az do presenteru

co se tyce tovarny, pouziti zde by melo bejt v poradku, tento form se pouziva na vice mistech v systemu… a pokazde by se mel tedy i jinak renderovat (cimz se vracime na zacatek – v soucasnosti je to komponenta dedici od ‚Control‘ (diky cemuz mi to dovoli definovat vlastni udalost – napr. onSave[], je vytvarena tovarnou a v sablone ji vykresluju skrze {control newsletterForm}.

Abych to shrnul:

  1. komponenta tvorena tovarnou – vraci se mi objekt NewsletterForm (tj. ta komponenta), tam si navesim svoji vlastni udalost onSave[] napr., do ktere si hodim informaci, ze newsletter byl smazan nebo pridan
  2. druha moznost je tedy samotna trida jakozto samotna tovarna, ktera form vraci pri pouziti metody $tovarna->create(), vraci objekt ‚Form‘, ale nejsem schopen tam navesit moji vlastni udalost onSave[].. ALE zase jde vykreslit rucne pres {form newsletterForm}{/form} :)

(snad je to nyni srozumitelne)

a teď babo raď, jak z toho ven :)


EDIT: Samane, jeste jsem koukal na ten tvuj snippet z projektu todolist na githubu, presne takle normalne formy vytvarim, coz je ten zpusob b. co jsem popsal o par radku vyse

Editoval Ja (4. 3. 2015 10:48)

Šaman
Člen | 2668
+
0
-

Pořád nechápu v čem je problém

Jediné, so mě u tebe zarazilo je ta proměnná $status. Jestli to není tím, tak ukaž asi celý kód a co ti to hlásí za chybu. Musí na to jít navěsit události jak z továrny, tak z komponenty/presenteru, běžně to tak používám.

<?php
protected function createComponentNewsletterForm()
    {
        $form = $this->newsletter_form_factory->create();
        $form->onSuccess[] = function ($form, $status) { # <-- funkce dostane parametry $form a $values!
            // vypusteno
        };

        return $form;
    }
?>
Ja
Člen | 260
+
0
-

@Šaman :
komponenta:

<?php
class NewsletterForm extends Control
{
	// nejaka DIcka - vypusteno

    public $onSuccess; // vlastni udalost, klidne by se mohla jmenovat onSave... takle asi prepisuju standardni udalost onSuccess z Control

	// createComponentForm metoda - vypusteno

	public function formSucceeded($form, $values)
	{
        if($this->newsletter->findBy($values)) {
            $this->newsletter->deleteBy($values);
            $this->onSuccess($this, DbStatus::DELETED); // timto si dostanu do presenteru informaci o tom, ze je newsletter smazan, vytahnu si to
        }
        else{
            $this->newsletter->save($values);
            $this->onSuccess($this, DbStatus::SAVED);
        }
	}
?>

vstriknuti objektu v presenteru:

<?php
/** @var INewsletterFormFactory @inject */
    public $newsletter_form_factory;
?>

tvorba komponenty v presenteru pres tovarnu pro vykresleni v sablone:

<?php
protected function createComponentNewsletterForm()
    {
        $form = $this->newsletter_form_factory->create();
        $form->onSuccess[] = function ($form, $status) {

            if($status == DbStatus::DELETED) {
                $this->flashMessage('E-mail byl odstraněn.');
            }
            else if($status == DbStatus::SAVED){
                $this->flashMessage('E-mail byl přidán.');
            }

            $form->getPresenter()->redirect('default');

        };

        return $form;
    }
?>

jeste tedy pro uplnost ten interface:

<?php
interface INewsletterFormFactory
{

    /**
     * @return NewsletterForm
     */
    function create();
}
?>

je to takto jasnejsi? v tuto chvili dostavam NewsletterForm objekt na kterem muj vlastni onSuccess[] funguje, ale zas ten form rucne nevyrenderuju

diky moc

Editoval Ja (4. 3. 2015 11:46)

Ja
Člen | 260
+
0
-

nepohneme s tim? :)

bazo
Člen | 620
+
0
-

ved si ho vyrenderuj v sablone tej komponenty