Ajax – překreslení formuláře nenačte data

- d@rkWolf
- Člen | 172
Zdravím,
mám add/edit formulář na adresu v komponentně – když odstraním ajax,
vše funguje, data se uloží, redirect(this) reloadne stránku, formulář se
načte s nově uloženými údaji, změní se popisek tlačítka
(přidat->upravit).
Jak přidám třídu ajax, fungovat to přestane. Data se sice uloží, ale
dotaz v ActionDefault, který má ty uložené údaje načíst a vyplnit je do
formuláře vyjde s výsledkem null(ten bdump) – ten samý, který při
redirectu funguje správně. Díky tomu nezmění tlačítko a nedoplní id
záznamu, takže další úprava není možná. Je to u přihlášeného
uživatele, getId() vrací ID správně, pokud si dotaz s výsledkem null
skopíruju z Tracy do PhpMyAdmin, výsledkem je správně uložený řádek. Je
tam použitá Naja 1.8×.
Úplně mi uniká, kde je problém.
Presenter:
final class MyPresenter extends BasePresenter
{
use AddressFormFactory;
public function actionDefault(int $itemId): void
{
$address = $this->webAddressRepo->getByUser($this->getUser()->getId());
bdump($address);
if ($address) {
$addressForm =$this->getComponent('addressForm')['form'];
$addressForm->addHidden('id');
/** @var SubmitButton $send */
$send = $addressForm->getComponent('send');
$send->setCaption('Update address');
$addressForm->setDefaults($address);
}
}
}
Traita s továrnou komponenty
trait AddressFormFactory
{
#[Inject]
public IAddressFormFactory $addressFormFactory;
protected function createComponentAddressForm(): AddressForm
{
$control = $this->addressFormFactory->create($this->getUser()->getId());
$control->onSave[] = function (AddressForm $control) {
$control->flashMessage($this->translator->translate('Address saved'), 'alert alert-success');
if ($this->isAjax()) {
$control->redrawControl('form');
$control->redrawControl('flashes');
} else {
$this->redirect('this');
}
};
return $control;
}
}
šablona komponenty s formulářem (použil jsem bootstrap formátování jako je v jednom z Examples)
{import '../../Presenters/templates/@components/form-bootstrap5.latte'}
<div n:snippet="flashes" data-naja-history-nocache>
<div n:foreach="$flashes as $flash" n:class="alert, $flash->type, alert-dismissible, fade, show" role="alert">
{$flash->message}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
</div>
<div class="account-form-area" n:snippet="form">
{include bootstrap-form form}
</div>
v šabloně presenteru už je to pak vloženo jen takto:
{control addressForm}
Editoval d@rkWolf (8. 4. 2024 19:37)

- nefilskyl
- Člen | 2
Odhadoval bych, že by to mohlo souviset s životním cyklem presenteru.
Jako první se zpracuje action, potom handle. Jestli to chápu dobře, tak
zpracování formuláře je vlastně implementováno jako signál –
v každém formuláři se automaticky přidá hidden „_do“ s hodnotou
„<formular>-submit“, který způsobí to, že presenter najde ten
formulář v komponentách a invokuje příslušnou metodu
signalReceived($signal), konkrétně tedy
Nette\Application\UI\Form::signalReceived(‚submit‘), která zajistí
zpracování formuláře.
To znamená, že se stane toto:
- spustí se actionDefault – ještě tam nic není uloženo, takže je výsledkem null
- spustí se obsluha signálu addressForm-form-submit – data se uloží
- renderDefault – tady už by data byla k dispozici, ale metoda se zde nepoužívá, takže se nic nestane
- překreslí se šablona – ale formulář nemá data, takže to vypadá jako že se nic neuložilo.
Při redirectu to funguje, protože po zpracování formuláře server vrátí 302, prohlížeč provede nový request a presenter se spustí celý znovu.
Řešení:
- jako nejjednodušší úprava by asi stačilo přejmenovat actionDefault na renderDefault
- lepší mi ale přijde získávat data a nastavit defaultní hodnoty přimo v komponentě s formulářem (formulář už má k dispozici id uživatele, není problém tam injectovat závislost webAddressRepo a data si načíst tam).
Editoval nefilskyl (24. 4. 9:33)

- m.brecher
- Generous Backer | 920
@darkWolf
mám add/edit formulář na adresu v komponentně – když odstraním ajax, vše funguje, data se uloží, redirect(this) reloadne stránku, formulář se načte s nově uloženými údaji, změní se popisek tlačítka (přidat->upravit).
Toto je běžný use-case, kdy formulář nemá data, uživatel je vyplní a odešle , form data uloží, db poskytne id nového záznamu a form přesměruje na url pro editaci, kam přidá nově získané $id. vždy by to mělo být redirect, protože je potřeba změnit url, url pro nový záznam i editaci by neměl být stejný – formulář v těchto režimech pracuje jinak, jinak tahá data apod…
Já ve všech handlerech formů – vesměs jsou všechny ajax-submitted, ale funguje to i bez ajaxu v create() (uložení nového záznamu) mám $this->redirect(‚update‘, [‚id‘ ⇒ $id]), kde $id získám z databáze – po uložení záznamu!
Nette umí redirect standardní non-ajax i ajaxový – je ale potřeba, aby ajax knihovna uměla s ajaxovým redirectem správně zacházet. Já Naja nepoužívám, mám vlastní AjaxHandler.js, kde ajaxový redirect vyvolá změnu url – to je smyslem redirectu. Naja to jistě také umí, ale možná se jí musí nějak pomoct.
V tvojí traitě s buildem formu vidím přesměrování $this->redirect(‚this‘) – toto by teoreticky nemělo vůbec fungovat, protože se dostaneš na url pro nový záznam, ale neznám detaily třeba tam to id nějak dostaneš.
Redraw formuláře je OK po editaci záznamu – zde se url nemění, pro nový záznam doporučuji přesměrovat na url pro editaci – v ajaxu i non-ajaxu!
Jinak při redraw platí, že bys měl načítat data do formu v render fázi !! ne action.
Zkus redirect() i pro ajax!