Form multiplier id do formulára po uložení
- _rasel^
- Člen | 59
Ahojte, mám form multiplier a v ajaxovej akcii po uložení by som chcel dostať id, aby som zobrazil tlačidlo na mazanie. To mi funguje, ale nerobím to úplne ideálne, pretože ho do formulára dostanem cez $this->template->id:
public function updFormSucceeded(UI\Form $form, $values) {
$this->template->id = $this->db->table('table')->insert($values)->id;
$this->redrawControl("formSnippetArea");
$this->redrawControl("cpBtnSnippet");
}
A viem takto vykresliť tlačidlo na mazanie:
{snippet cpBtnSnippet}
{ifset $id}<a href="{plink del! id => $id}" class="btn btn-default ajax">Vymazať</a>{/ifset}
{/snippet}
Komplikácia nastáva, ak to chcem robiť pre riadky multiplieru. Myslel som si, že to pôjde takto:
public function updFormSucceeded(UI\Form $form, $values) {
$data = ['id', ['multiplier' => ['lid' => 55]]];
$form->setDefaults($data);
$this->redrawControl("formSnippetArea");
$this->redrawControl("cpSnippet");
}
lid sa do $_multiplier->components[‚lid‘]->value nedostane a je tam stále hodnota ''. Kde robím chybu?
Editoval _rasel^ (14. 4. 2023 15:06)
- Marek Bartoš
- Nette Blogger | 1274
Nedává smysl nastavovovat do formuláře výchozí hodnoty poté, co byl
formulář úspěšně odeslán, setDefaults() by mělo být rozhodně jinde
V $data
máš jako hodnotu 'id'
, nechtěl jsi ho
použít spíš jako klíč?
Neznám strukturu tvého formuláře s multiplierem, ale myslím, že jsi se
pokoušel spíš o něco takového:
$data = [
'multiplier' => [
[
'lid' => 1,
],
[
'lid' => 2,
],
// ... další položky
],
];
Editoval Marek Bartoš (14. 4. 2023 16:24)
- _rasel^
- Člen | 59
Predstav si, že máš formulár, ktorý sa zobrazuje ako modálne okno. Po otvorení modálneho formulára je v móde insert, tzn. dáta sa vkladajú do databázy a okno sa nezatvára. Následne sa načíta id hlavičky a riadkov v štruktúre formulára, ktorú si popísal. Ak chceš editovať dáta, je potrebné znovu načítať dáta do formulára po odoslaní, aby si mohol aktualizovať údaje a hlavne id, aby si bol v móde update. Bohužiaľ, pri použití setDefaults() v akcii updFormSucceeded je id prázdne (ako som popísal vyššie) a setDefaults nefunguje. Preto som použil „hack“ $this->template->id – to mi funguje, ale určite to nie je správny postup. Na druhej strane, ak zatvorím a opäť otvorím formulár, tak sa dáta načítajú pomocou setDefaults() správne. Mal som dojem, že setDefault() môžem použiť v akcii a aj v updFormSucceeded a prekresliť snippet do ktorého je formulár obalený, ale nefunguje to a tu je pes zakopaný. Má s tým niekto skúsenosti?
Editoval _rasel^ (15. 4. 2023 9:52)
- _rasel^
- Člen | 59
Áno, chápem, to je v poriadku. Štandardne sa hodnoty pomocou setDefaults inicializuj vo funkcii render<nieco>, alebo action<nieco> – to funguje bez problémov. Položím otázku inak: kde mám použiť funkciu setDefaults, ak chcem hodnoty vo formulári nastaviť po odoslaní formulára a formulár, ktorý je obalený v snippete prekresliť?
Editoval _rasel^ (19. 4. 2023 10:31)
- m.brecher
- Generous Backer | 871
@_rasel^
To co popisuješ – formulář v insert módu se po odeslání přepne do update módu a nasosá si aktuálně odeslaná data je standardní způsob použití formulářů a bez ajaxu v presenteru se řeší snadno přesměrováním. Formuláře Nette totiž pracují ve dvou fázích a) vykreslení, kdy se vykreslují defaultValues a b) zpracování submitu, kdy se vykreslují submitem odeslaná data ($values). Ve formuláři který BYL ODESLÁN nemá význam volat setDefaultValues(), tyto data se nepoužijí. Redirect to řeší, protože se formulář znovu vykreslí a defaultData zobrazí.
Jak fungují módy formuláře (vykreslený/odeslaný) v ajaxu jsem hledal v dokumentaci Nette v sekci Ajax, ale tam o ajaxových formulářích nic není. Jsou tam ale tyto základní informace:
a) AJAXový požadavek se nijak neliší od klasického požadavku – je zavolán presenter s určitým view a parametry.
b) Snippety – Vykreslování stránky probíhá velmi podobně jako při běžném požadavku: načtou se stejné šablony atd.
Při pohledu na tyto informace bych odhadnul, že i když formulář překreslíš, nezměníš jeho vnitřní stav $form->isSubmitted() === true a defaultValues se vykreslovat nebudou. Formulář se překreslí, můžeš tam přidat/ubrat nějaké prvky, ale ten stav „formulář byl odeslán“ takhle nezměníš. Zkus to vyzkoušet, jestli se submitnutý formulář po překreslení přepne do $form->isSubmitted() === false, uvidíš.
Co bys potřeboval je na úrovni modálního ajaxového okna realizovat redirect toho modálního okna s možností změny módu formuláře na „vykreslený“. Je docela možné, že to nepůjde, ale třeba se nějaké řešení najde.
Štandardne sa hodnoty pomocou setDefaults inicializuj vo funkcii render<nieco>, alebo action<nieco>
Ajax funguje jako signál, tj. pod úrovní aktuálního presenter:action, takže se vykonají stejné metody jako při načtení stránky, můžeš si otestovat, zda je request ajaxový a modifikovat vykonání těch metod, ale myslím, že zase narazíš na to, že je formulář již odeslaný.
Editoval m.brecher (19. 4. 2023 13:53)
- _rasel^
- Člen | 59
Redirect nemôžem urobiť, keďže je to ajaxové modálne okno a modálne okno žije v action a môže byť v úplne inom presenteri. Ak urobím redirect, tak ma presmeruje na presenter v ktorom je modálne okno a to nie je žiadaný stav.
Nakoniec som to vyriešil takto (zjednodušený kód nižšie). Určite to nie je ideálne, ale funkčné riešenie – možno niekomu pomôže, alebo rozprúdi debatu iným smerom.
public function actionModal($id)
{
if(isset($id)) {
$form = $this['cpForm'];
...
$data = array_merge($dataH, ['multiplier' => $dataL]);
$form->setDefaults($data);
$this->template->id = $id;
$this->template->mul = $this->db->getRows($id);
}
}
public function updCpFormSucceeded(UI\Form $form, $values) {
$id = (int) $this->getParameter('id');
if ($this->isAjax()) {
$this->payload->isModal = true; // nezatvárame okno
}
$insId = $this->db->updCp($id, $values); // ak je id null, tak je insert, inak update a fn() vráti inserted id
if(isset($insId)) {
$this->template->id = $iuId;
$this->template->mul = $this->db->getRows($insId); // insId je id hlavičky
$this->redrawControl("formSnippetArea");
$this->redrawControl("cpBtnSnippet");
$this->redrawControl("cpSnippet");
}
$this['dataGrid']->reload();
}
<div n:multiplier="multiplier">
{ifset $mul}
{php $mid = $mul->fetch()->lid ?? null}
{ifset $mid}
<a href="{plink pdf!, l => $mid}" role="button" target="_blank" class="btn btn-sm btn-default">PDF</a>
<a href="{plink pdf2!, l => $mid}" role="button" target="_blank" class="btn btn-sm btn-default">PDF2</a>
{/ifset}
{/ifset}
</div>
...
{snippet cpBtnSnippet}
<div class="modal-footer">
{ifset $id}<a href="{plink del! id => $id}" class="btn btn-default ajax">Vymazať</a>{/ifset}
</div>
{/snippet}
Editoval _rasel^ (19. 4. 2023 14:36)
- m.brecher
- Generous Backer | 871
@_rasel^
Redirect nemôžem urobiť, keďže je to ajaxové modálne okno a modálne okno žije v action
Přesně tak, nejde to, ale něco takového bychom potřebovali mít, ne redirect celého presenteru, ale nějakou feature, která by ten redirect dokázala naemulovat – přesněji přepnutí formuláře do výchozího vykreslovacího módu. Formuláře Nette jsou totiž bohužel příliš těsně vázány na presentery a v modálním ajaxovém okně to dělá problémy.
- m.brecher
- Generous Backer | 871
_rasel^ napsal(a):
public function actionModal($id) { if(isset($id)) { $form = $this['cpForm']; ... $data = array_merge($dataH, ['multiplier' => $dataL]); $form->setDefaults($data); $this->template->id = $id; $this->template->mul = $this->db->getRows($id); } }
Zajímavé řešení. Mám dva dotazy:
a) Formulář s daty pro nový záznam odesíláš ajaxem, jak dostaneš do actionModal($id) id záznamu uloženého do databáze ? Ajax je signál a neměl by měnit parametry v url ??
b) Po překreslení formuláře aniž by se provedl redirect vykreslí formulář defaultní data $form->setDefaults($data) ??
- _rasel^
- Člen | 59
- Parametre v url ajaxom nemením, id do action dostávam len ak sa fomulár edituje po opätovnom otvorení – čiže vtedy už používam klasický prístup. Ajaxom parametre nemení z dôvodu, že netuším ako to docieliť – čo by bolo asi riešením – ak sa dá ajaxovo zmeniť parameter v url bez redirectu a zároveň prekresliť obsah modálneho okna. Ideálne by bolo asi niečo takéto: https://forum.nette.org/…ny-presenter ale ajaxRedirect s parametrom, nie len setView.
- setDefaults v updCpFormSucceeded nepoužívam, keďže aj napriek použitiu setDefaults a prekreslení a vydumpovaní $_multiplier->components nemalo na dáta žiaden vplyv – ako keby som fn ani nepoužil. Preto to obchádzam $this->template a tam si hodím dáta aké potrebujem. Blbé je, že by som predsa len potreboval id hlavičky a id riadkov dostať (id hlavičky do paramtra url a id riadkov do $_multiplier), pretože po prvom uložení bez zatvorenia formulár už id má a mal by sa editovať. A keďže id vo values zo setDefaults nemám, tak sa záznamy po opätovnom uložení insertrujú a nie updatujú. Takže $this->template->id musím cez templat dostať do nejakého inputu. Nastavovanie inputu pomocou $this->template mi nepríde ako šťastné riešenie, ale nemám na výber – aspoň týmto smerom sa asi budem uberať, nič lepšie ma nenapadá. Inak by som musel po prvom kliknutí na uložiť zrušiť tlačidlo uložiť a existovalo by len tlačidlo zavrieť. Po opätovnom otvorení formulára už funguje setDefaults klasický (už viem id z parametrov a id riadkov zo setDefaults z action), takže tento problém už nie je. Ku takémuto stavu, ktorý je potrebné takto ošetrovať dochádza len vtedy, ak dáta insertujem a po uložení formulára bez zatvorenia chcem ešte editovať nejaké položky, alebo zobraziť nejaké tlačidlá, ktoré má zmysel vykresliť len vtedy ak už viem id, alebo id riadka ku ktorému sa vzťahujú.
Poznámka: skúšam js (natvrdo id ktoré existuje), ale komplikácia v tomto prípade bude, že potrebujem urobiť submit formulára, zmenu url a redraw. Tracy hlási, že došlo z ajaxovej požiadavke, ajaxový presenter, action a aj id sedí, ale nedošlo k prekresleniu napriek tomu, že redraw v action mám. Opäť robím niečo nesprávne…
<script type="text/javascript">
$('.save').click(function(){
$.ajax({
'url': {plink modalCp, id => 121},
'data': {
}
});
return false;
});
</script>
Editoval _rasel^ (19. 4. 2023 17:07)
- m.brecher
- Generous Backer | 871
@_rasel^
setDefaults v updCpFormSucceeded nepoužívam, keďže aj napriek použitiu setDefaults a prekreslení a vydumpovaní $_multiplier->components nemalo na dáta žiaden vplyv
To je bezpochyby způsobeno tím, že formulář po ajaxovém submitu je v módu $form->isSubmitted() === true a tehdy nevykresluje defaultValues ale values (data odeslaná od uživatele). Kdyby Jsi chtěl předat $id rovnou do formuláře např. do input hidden pro mazání tlačítkem formuláře, použil bych místo $inputHidden->setDefaultValue($id) public interní $inputHidden->setValue($id), to by fungovat mělo.
Když ale použiješ k mazání signál v odkazu zapsaný přímo v šabloně, tak je v pořádku předat $id do šablony a je to asi i nejjednodušší řešení.
- _rasel^
- Člen | 59
Skúšal som aj setValues, ale došiel som k záveru, že hodnoty z formulára síce zmeniť viem, ale môžem ich poslať tak smerom do control (jednosmerný lístok), ale neviem ich poslať smerom do presenteru v updCpFormSucceeded + redraw snippetu.
public function updCpFormSucceeded(UI\Form $form, $values) {
$form->setValues(['Od' => 'abraka-dabra']);
bdump($form->getValues()); -- hodnoty zmenené sú ale nezobrazia so vo formulári
//$form->setDefaults(['Od' => 'brekeke']);
$this->redrawControl("formSnippetArea");
$this->redrawControl("cpBtnSnippet");
$this->redrawControl("cpSnippet");
}
Editoval _rasel^ (20. 4. 2023 9:42)
- _rasel^
- Člen | 59
Takže to riešim takto. Na fetch() si treba dať pozor. Select musí byť zotriedený v takom poradí v akom sú riadky multiplieru, keďže nad n:multiplier=„multiplier“ nie je foreach/index, tak získanie hodnoty riešim práve fetchom().
<div n:multiplier="multiplier" class="modal-content row"
{ifset $mul}{php $mid = $mul->fetch()->lid ?? null}
... nejaké tlačidlá, ktoré potrebujeme v hlavičke formulára ak už vieme id riadka
{/ifset}
<input type="hidden" id="lid" name="lid" value="{ifset $mid}{$mid}{/ifset}">
</div>
Edit: Iba upresním, že setValues() funguje nad klasických formulárom a nie je problém s ajaxovým refreshom. Ale z nejakého dôvodu nie je funkčný pre položky multiplieru.
Editoval _rasel^ (24. 4. 2023 16:26)