Vytvoření a zpracování dynamického formuláře

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

Mám začátečnický dotaz na vytvoření formuláře. Mohu vytvořit formulář tak, že vytvořím jen „obálku“, tady definuji jen form a submit

protected function createComponentVybermestaForm()
{
    $form = new Form();
    $form->addSubmit('create', 'Nastavit')
         ->setAttribute('class', 'ulozit');
    $form->onSuccess[] = callback($this, 'vybranoFormSubmitted');
    return $form;
}

a v render vytvořím pole hodnot

public function render()
    {
    $i=1;
    foreach($this->mesta as $m){
    		$mesta[$i]['id']=$m['id'];
    		$mesta[$i]['name']=$m['name'];
    		$i++;
				}

			$this->template->mesta = $mesta;
    			$this->template->setFile(__DIR__ . '/Mesta.latte');
    			$this->template->render();
    }

S tím, že to v šabloně jen složím?

{form vybermestaForm}
		{foreach $mesta as $mesto}
                        {first}<table>{/first}
                          {first 4}<tr>{/first}
                            <td><input type="checkbox" name="{$mesto['name']}" value="{$mesto['id']}">{$mesto['name']}</td>
                          {last 4}</tr>{/last}
                        {last}</table>{/last}
                      {/foreach}

                      {input create}

                    {/form}

Nebo ty checkboxy musím vytvářet ve formuláři?
Jde mi o to, že nevím, kolik položek je v databázi. Zkusil jsem to takto, ale po odeslání formuláře se nic nestane. Potřebuji, aby se vytvářela sessions a bohužel se mi to nedaří.

 public function vybranoFormSubmitted(Form $form)
{
     foreach ($form->values as $mes => $me ){
     $section = $this->section;
     $section->$mes = 'ok';
    }

    $this->flashMessage('Zkouška', 'success');
    $this->redirect('this');


  }

Ani flashMessage se nezobrazí. Toto vše mám v komponentě, ne v presenteru, ale vykreslování funguje bez problému. Teď ale nevím, zda nedělám chybu při vytváření a odeslání formuláře, nebo je někde zakopán pes v tom, že to není v presenteru. Budu vděčný za každou pomoc.

JakubJarabica
Gold Partner | 184
+
0
-

Formulár ked už, tak doupravuj v action. Pri submite sa totiž musi zložiť už v action, render fáza je az po spracovaní signálov. Údaje na vytvorenie formu si môžeš vytiahnuť aj vo factory metóde(parametre presenteru sú v $this->params). Tak získaš aj lazy loading(v actione ho vytvoríš a v šablóne ho nemusíš vykresliť).

llook
Člen | 407
+
0
-

Takhle se to udělat nedá. Formuláře v Nette berou v potaz pouze pole, která jsou definovaná a v momentě kdy se provádí onSuccess máš definovaný pouze ten submit.

Ani kdybys ta pole opravdu definoval v té šabloně (přes $form->addCheckbox), tak by to nefungovalo, protože onSuccess se provádí před renderem a tedy před zpracováním šablony.

Zkrátka si ten formulář nadefinuj celý v té továrničce createComponentVybermestaForm, nějak takhle:

protected function createComponentVybermestaForm()
{
    $form = new Form();
    $form->addSubmit('create', 'Nastavit')
         ->setAttribute('class', 'ulozit');
    $form->onSuccess[] = callback($this, 'vybranoFormSubmitted');

    $form->addGroup('mesta');
    foreach($this->mesta as $m){
        $form->addCheckbox($mesta['id'], $mesta['name']);
    }

    return $form;
}

A v šabloně ho vykreslíš nějak takhle:

{? $form = $control['vybermestaForm']}
{form $form}
	<ul n:if="$form->errors" class="errors">
		<li n:foreach="$form->errors as $error">{$error}</li>
	</ul>

	<table>
		{foreach $form->groups['mesta'] as $name => $field}
			{first 4}<tr>{/first}
			<td>{input $name} {label $name /}</td>
			{last 4}<tr>{/last}
		{/foreach}
	</table>

	{input create}
{/form}
uestla
Backer | 799
+
0
-

(Možná jen přepíšu to, co psal přede mnou JAM3SoN [edit] a llook [/edit], ale přece:)

Jednak nemáš formulář dodefinován, ale bokem mimo Nette si vytváříš inputy ručně v šabloně – to samo už není dobré a Nette pak nemá odkud získat hodnoty.

Druhak by to chtělo v místě, kde předáváš pole $mesta komponentě (tedy např. v továrničce na komponentu někde v nadřazené komponentě (např. presenteru)), rovnou sestavit formulář, čili ty checkboxy vytvořit – nejlépe do containeru.

A za třeťak se mi nezdá kód, cos poslal, je nějaký upravovaný asi. Na to, co děláš tak složitě v iteraci, existuje funkce array_values().

Možné řešení:

// presenter:
protected function createComponentCities()
{
	$cities = new CitiesControl;
	$cities->setCities( Model::getCitiesList() );
	return $cities;
}

// CitiesControl:
function setCities(array $cities)
{
	$this->cities = array_values($cities);
}

protected function createComponentCitiesForm()
{
	$form = new UI\Form;
	$container = $form->addContainer('cities');
	foreach ($this->cities as $city) {
		$container->addCheckbox($city['id'], $city['name']);
	}

	$form->addSubmit('create', 'Nastavit');
	// onSuccess ...
	return $form;
}

šablona komponenty:

{control citiesForm}

PS: ohledně té nezobrazené flashMessage – zdálo by se na první pohled, že se nedetekovalo odeslání formuláře, nicméně to by se dle mého detekovat mělo. Problém nejspíš bude v tom, že nikde v šabloně komponenty, ve které tu flashMessage vytváříš, flash messages nevykresluješ. Buď je vykresluj v komponentě, nebo je vytvářej pro presenter ($this->presenter->flashMessage()).

Editoval uestla (9. 6. 2012 9:07)

Musilda
Člen | 12
+
0
-

Díky všem za rady, jen ještě, jak mám vytvořit zaškrtnutý checkbox, toto nefunguje

$container->addCheckbox($city['id'], $city['name'])
                      ->setValue(1);
llook
Člen | 407
+
0
-

To je divný, tohle by fungovat mělo a mě to všude funguje.

Musilda
Člen | 12
+
0
-

Já jsem to do toho přidal, abych si to vyzkoušel, než začnu psát podmínku a mělo by se zaškrtnout všechno, co se vypíše, ale neděje se tak. Doufám, že budete mít trpělivost s lamou jako jsem já.

zimmi
Člen | 94
+
0
-

@llook zkouším naplnit formulář tak, jak jsi psal, tj. v cyklu foreach. Plním ho z proměnné $this->rivers, která je výsledkem dotazu do DB. Když si však po proběhnutí cyklu dumpnu formulář, zjistím, že neobsahuje žádné komponenty, ačkoliv $this->rivers obsahuje přesně to, co obsahovat má. Plnění formuláře vypadá takto:

protected function createComponentExportForm()
    {
        //Debugger:dump($this->rivers);
        $form = new AppForm;
        $form->onSuccess[] = callback($this, 'exportFormSent');
        foreach ($this->rivers as $r) {
            $idvt = (int)$r->idvt;
            $form->addCheckbox('c_'.$idvt, 'c_'.$idvt);
        }
        return $form;
    }