Pozdější naplnění selectu formulářové komponenty
- jarks
- Člen | 94
Dobrý den, prosím o radu. Výsledkem tohoto kódu je, že hodnota
formulářového pole hidden
se v pořádku dostane až k metodě
pro obsluhu odeslání a hodnota pole select
se tam nedostane.
Nemůžu zjistit proč.
class TestPresenter extends BasePresenter {
protected function createComponentEditForm() {
$form = new AppForm();
$form->addHidden('id');
$form->addSelect('ciselnik', '');
$form->addSubmit('ulozit', 'Uložit');
$form->addSubmit('zrusit', 'Zrušit');
$form->onSubmit[] = array($this, 'Form_Submit');
return $form;
}
public function handleEdituj($editId) {
$ciselnik=array('1'=>'prvni', '2'=>'druhy'); // ve skutečnosti z dababáze
$this['editForm']['id']->value = $editId;
$this['editForm']['ciselnik']->items = $ciselnik; //<< tady je asi něco špatně, ale zobrazí se správně
}
public function Form_Submit(Form $form) {
$values = $form->getValues();
Debug::dump($values);
// výsledek: $id == číslo, $ciselnik == NULL
}
} // class
Select se správně včetně hodnot vykreslí, ale po odeslání formuláře
se z něj nic nepřenese.
Jestliže naplnění položek selectu dám do továrničky
($form->addSelect('ciselnik', '',array('1'=>'prvni', '2'=>'druhy'))
tak je všechno v pořádku. Továrnička ale nemůže vědět, co bude třeba
zobrazit. To se řídí proměnnou $editId
předanou teprve až
handleru.
Je mi divné, že obě hodnoty jsou nastavené stejným způsobem a jedna přitom zůstane prázdná.
- Patrik Votoček
- Člen | 2221
Zkus místo
$this['editForm']['ciselnik']->items = $ciselnik;
použít
$this['editForm']['ciselnik']->setItems($ciselnik);
je tam kolem
toho nějáká magie viz: https://api.nette.org/…Box.php.html#148
Obecne doporucuju pouzivaz pri vkladani dat do formu set metody…
nejak jsem zapomel na syntactic sugar (mel bych jit spat)
Editoval vrtak-cz (24. 8. 2009 2:42)
- jasir
- Člen | 746
Pro nastavení defaultních hodnot formuláře nepoužívej
setValue()
(ani syntactic sugar ->value = ...
), ale
metodu setDefaults
:
<?php
$this['editForm']->setDefaults( array('id'=>$editId));
//nebo alternativně (doufám):
$this['editForm']->defaults = array( 'id'=>$editId);
?>
Editoval jasir (24. 8. 2009 1:39)
- jarks
- Člen | 94
Díky pánové, v tuto dobu jsem odpověď nečekal.
Bohužel ->setItems
má stejný výsledek, tedy žádný. A
->setDefaults
je snad k něčemu jinému. Tady jde
o naplnění celého selectu, nikoliv o to, která jeho položka má být
vybraná. I tak jsem to zkusil
$def = array('ciselnik' => array('1'=>'prvni', '2'=>'druhy');
$this['editForm']->setDefaults($def);
ale neúspěšně.
- jasir
- Člen | 746
Mě se nějak nezdá ten název metody handleEdituj
. Podle mě
se při submitu nevolá, a proto je ten form rozsekanej. Proč to máš takhle
nevím, ale typicky by jsi měl upravovat formulář (aby byl kompletní) před
fází zpracování signálů. Například v metodě
actionEdituj
.
Editoval jasir (24. 8. 2009 2:11)
- Patrik Votoček
- Člen | 2221
Jasir má pravdu teď mě to nakoplo a docvaklo. Pokud odešleš formulář
nette volá signál „submit“ který převezme
$form->onSubmit
. A tím pádem se na tvůj signál „edit“
nedostane. Editování by měla být action a né signál. Signál bych
používal na něco jiného.
Jde vůvec v nette docílit volání 2 signálů při jednom požadavku??
PS: snad nepíšu blbosti…
Edit: teď mě tak napadlo že by to teoreticky šlo oblbnout asi takto ale netestoval jsem.:
$form->addSubmit('zrusit', 'Zrušit');
$form->onSubmit[] = array($this, 'handleEdit'); //<-- tenhle radek jsem pridal ale nenapada me jak mu predat parametr s IDckem...
$form->onSubmit[] = array($this, 'Form_Submit');
return $form;
Editoval vrtak-cz (24. 8. 2009 2:57)
- jarks
- Člen | 94
Díky. Ale proč u jednoho údaje ($id) k naplnění hodnoty dojde a u druhého ne? Nemůže to být nějaká chyba v Nette?
Zkusím popsat, proč to tak dělám, třeba je to špatně. Důvod je ten, že na stránce je odkaz, ten
- zavolá signál, který obstará nastavení pomocné proměnné, která určuje zda se zobrazí odkaz nebo formulář.
- zároveň u položek, kde je to třeba, bez problémů naplní formulář defaultními hodnotami.
Na místě odkazu se zobrazí formulář, uživatel vyplní nebo vybere, odešle a opět se zobrazí odkaz. Prostě „in place editing“. Používám ajax, ale popisovaný problém se projeví ajax neajax.
V šabloně je:
{snippet polozka span}
{if $editItem != 'polozka'} // $editItem je pomocná proměnná
<a href="{link handleEdituj!, 'editId' => $p->id, 'editItem' => 'polozka'}" class="ajax">{$p->nazev}</a>
{else}
{control editForm} // když handle nastaví pomocnou proměnnou, místo odkazu se zobrazí formulář
{/if}
{/snippet}
Na dané stránce je tento postup bez problémů použit mnohokrát u textových položek i selectů. Problém nastal až teď, kdy potřebuji v handle naplnit celý select. Všechno se správně zobrazí, ale hodnota se nepředá. Bohužel nevím jak jinak předat komponentě ID podle kterého si má sestavit formulářový select.
- Panda
- Člen | 569
Je to jednoduché – Nette při odeslání formuláře kontroluje, jestli zadaná data vyhovují definicím (tzn. aby nešlo modifikovat odesílaná data nebo si do selectu přidat volbu, ke které by neměl mít přístup). V případě onoho selectu se kontroluje, zda zaslaná hodnota je jedna z těch, které select nabízí. Háček je v tom, že v Tebou vytvořeném formuláři select nenabízí vůbec nic. Ty sice někde ze stránky zavoláš signál a selectu se požadované možnosti přidají, ale jen pro zbytek požadavku, ve kterém je signál volán. Při odeslání formuláře se opět vytvoří jeho instance, kde je select bez vyplněných hodnot, které může nabývat, validace odeslané hodnoty tedy neprojde, a tak se zdá, že hodnoty nebyly nastaveny.
//Doplnění: u textových polí k této kontrole nedochází – formulář nemá informaci o tom, jakých hodnot může prvek nabývat. Proto jsi s nimi neměl problémy.
K vyřešení problému budeš muset trochu předělat koncept, jakým
s formulářem pracuješ – jeho definice by neměla být závislá na
volání nějakého signálu. Logiku je potřeba přesunout do metody
action<action>()
.
Zmiňované přidání signálu do události onSubmit
fungovat
nebude – hodnoty jsou v době volání události již zpracované a
ořezané. Navíc se signálu nepředá parametr $editId
(resp. on
se předá, ale bude obsahovat instanci AppForm
místo
zamýšlených dat), ve kterém, jak se zdá, celé řešení stojí.
// Poznámka: ještě zkusím dopsat návrh kódu, který by měl fungovat
// Doplnění slíbeného kódu:
TestPresenter
:
<?php
class TestPresenter extends BasePresenter {
public function actionEdit($editId = NULL, $editItem = NULL) {
if ($editId) {
// Zde bude podobný kód, jako v původním signálu
$ciselnik=array('1'=>'prvni', '2'=>'druhy'); // ve skutečnosti z dababáze
$this['editForm']['id']->value = $editId;
$this['editForm']['ciselnik']->items = $ciselnik;
}
$this->template->editItem = $editItem;
}
protected function createComponentEditForm() {
$form = new AppForm();
$form->addHidden('id');
$form->addSelect('ciselnik', '');
$form->addSubmit('ulozit', 'Uložit');
$form->addSubmit('zrusit', 'Zrušit');
$form->onSubmit[] = array($this, 'Form_Submit');
return $form;
}
public function Form_Submit(Form $form) {
$values = $form->getValues();
Debug::dump($values);
// výsledek: $id == číslo, $ciselnik == NULL
// Na konci handleru by měl být v ostrém nasazení redirect:
if (!$this->isAjax())
$this->redirect('edit');
else
$this->template->editItem = NULL;
// U AJAXového odeslání formuláře bychom měli vyresetovat
// pomocnou proměnnou, jinak by formulář zůstal stále zobrazený
}
} // class
?>
Šablona:
{snippet polozka span}
{if $editItem != 'polozka'}
<a href="{link edit, 'editId' => $p->id, 'editItem' => 'polozka'}" class="ajax">{$p->nazev}</a>
{else}
{control editForm}
{/if}
{/snippet}
Uvedené řešení má navíc jednu výhodu – pokud by z nějakého
důvodu v původním formuláři došlo během jeho zpracování k ošetřené
chybě (například validace Mime-Type
u nahraného souboru,
který nelze ověřit JavaScriptem, nebo pokus o vložení duplicitního ID),
formulář by uživateli zmizel a nic by se nedozvěděl – nebyl by zavolán
signál a proměnná $editItem
by nebyla k dispozici.
U řešení, které jsem napsal, uživateli formulář zmizí až v momentě,
kdy je vše v pořádku odesláno a zpracováno.
Editoval Panda (24. 8. 2009 9:52)
- jarks
- Člen | 94
Díky moc. Prozatím mi to nefunguje a zdá se, že problém je
v přiřazení pomocné proměnné
$this->template->editItem = $editItem;
v action. Není
možné, že se proměnná přiřadí jiné nebo žádné proměnné, protože
action neví co se vykresluje?
Template se jmenuje ‚detail‘, zkoušel jsem použít $this->setView(‚detail‘), ale ani tak nic.
//edit: Když vypnu ajax, vytvořím pokusně šablonu
detail.edit.phtml
, kterou po mě laděnka chce a dám do ní
{dump}
, správně nastavené editItem
v ní vidím,
ale myslím, že ajaxem do původní šablony se to nenastaví.
Editoval jarks (24. 8. 2009 14:56)
- Panda
- Člen | 569
jarks napsal(a):
Díky moc. Prozatím mi to nefunguje a zdá se, že problém je v přiřazení pomocné proměnné
$this->template->editItem = $editItem;
v action. Není možné, že se proměnná přiřadí jiné nebo žádné proměnné, protože action neví co se vykresluje?Template se jmenuje ‚detail‘, zkoušel jsem použít $this->setView(‚detail‘), ale ani tak nic.
//edit: Když vypnu ajax, vytvořím pokusně šablonu
detail.edit.phtml
, kterou po mě laděnka chce a dám do ní{dump}
, správně nastavenéeditItem
v ní vidím, ale myslím, že ajaxem do původní šablony se to nenastaví.
Pokud se tvůj action jmenuje detail
, tak si samozřejmě
musíš metodu přejmenovat…
<?php
class TestPresenter extends BasePresenter {
public function actionDetail($editId = NULL, $editItem = NULL) {
// ...
}
// ...
public function Form_Submit(Form $form) {
// ...
if (!$this->isAjax())
$this->redirect('detail');
// ...
}
} // class
?>
Template se pak bude jmenovat detail.phtml
a bude umístěný ve
složce templates/Test
(podle TestPresenter
).
Uvedený kód mi fungoval (včetně AJAXu).
// Doplnění: jinak teď jsem si ještě všiml, že snippet balíš do
prvku span
. To není moc dobré, vzhledem k tomu, že
span
je řádkový element a form
blokový.
Doporučuji span
změnit na div
.
Editoval Panda (24. 8. 2009 15:19)
- jarks
- Člen | 94
Panda napsal(a):
Pokud se tvůj action jmenujedetail
, tak si samozřejmě musíš metodu přejmenovat…
Už to konečně funguje, jen kvůli ajaxu jsem k action ještě musel přidat
$this->validateControl();
$this->invalidateControl('polozka');
Dobře a srozumitelně jste mi už po několikáté poradil. Jsem začátečník a moc si toho vážím.
// Doplnění: jinak teď jsem si ještě všiml, že snippet balíš do prvku
span
. To není moc dobré, vzhledem k tomu, žespan
je řádkový element aform
blokový. Doporučujispan
změnit nadiv
.
Uvědomuji si to, ale jde o položky v tabulce a potřebuji aby formulář zůstával v řádku.