Existuje u formuláře něco jako $form->addSuccess(‚Email was sent successfully.‘);
- vosy
- Člen | 532
Existuje nějaká alternativa k $form->addError(‚Email se nepodarilo odeslat.‘); pro úspěšné odeslání?
rád bych něco jako:
$form->addSuccess('Email was sent successfully.');
a v šabloně
<div n:if="$form->ownErrors" class="alert alert-{$Constants::MSG_TYPE_ERROR} alert-flashing">
<ul>
<li n:foreach="$form->ownErrors as $error">{$error}</li>
</ul>
</div>
<div n:if="$form->successMessages" class="alert alert-{$Constants::MSG_TYPE_ERROR} alert-flashing">
<ul>
<li n:foreach="$form->successMessages as $message">{$message}</li>
</ul>
</div>
- m.brecher
- Generous Backer | 873
@vosy
Formuláře Nette nemají vestavěný mechanismus pro zobrazení zprávy po úspěšném uložení dat. Toto zajišťují Flash zprávy, které se aktivují buďto v presenteru, nebo v komponentě poděděné z Nette\Application\UI\Control.
Pokud chceš, aby formulář „sám o sobě uměl“ odeslat success zprávu, používej doporučovaný postup, kdy se formulář umístí do samostatné komponenty poděděné z třídy Control a má vlastní šablonu. Do této šablony vložíš kód pro vykreslení flash zprávy komponenty a handlery formuláře umístíš ideálně také dovnitř této komponenty. Je s tím sice více psaní, ale ve výsledku máš formulář zcela nezávislý na presenteru, který mimo jiné bude umět i sám podat zprávu o výsledku požadované akce.
Koncept popisuje tento článek z dokumentace: https://doc.nette.org/…s/form-reuse#…
class MyForm extends Nette\Application\UI\Control;
{
public function __construct(
private readonly MyModel $myModel,
private readonly ?int $id,
)
{}
protected function createComponentForm(): Nette\Application\UI\Form
{
$form = new Nette\Application\UI\Form;
// sestavení formuláře
$form->onSuccess[] = $this->processSuccess(...); // syntaxe PHP 8.1 pro callback
return $form;
}
public function processSuccess(array $values): void
{
// zpracování
$this->flashMessage('povedlo se', 'success'); // zprávu předáme do flashes komponenty
}
public function render(): void
{
// data do šablony, je-li potřeba $this->template->abc = $abc;
$this->template->render(__DIR__.'/myForm.latte');
}
}
a flashes vykreslíme v šabloně komponenty myForm.latte
{form 'form'}
<div class="flash-box">
{foreach $flashes as $flash}
{* vykreslení zpráv *}
{/foreach}
</div>
{/form}
Formulář vložíš do šablony akce presenteru:
{control 'myForm'}
Aby to celé fungovalo, je potřeba komponentu MyForm vložit do presenteru pomocí factory:
final class MyPresenter extends BasePresenter
{
private ?int $id = null; // pomocná property pro předání parametru id do formuláře
public function __construct(
private MyFormFactory $myFormFactory,
// ....
)
{}
public function actionUpdate(int $id)
{
$this->id = $id; // uschováme id z url pro komponentu
}
protected function createComponentMyForm(): MyForm
{
return $this->myFormFactory->create(id: $this->id); // předáme id do formuláře
}
}
Factory formuláře se vygeneruje pomocí interface https://doc.nette.org/…tion/factory
Ve factory je potřeba deklarovat parametr $id předávaný z presenteru do komponenty:
interface MyFormFactory
{
public function create(?int $id): MyForm;
}
+ nezapomenout interface factory registrovat jako službu Nette !
Ve formuláři máš k dispozici jednak modelovou třídu, jednak parametr $id, tedy vše co potřebuješ pro správnou funkci formuláře. Ještě je možné tam předat mód formuláře update/create podle toho zda se formulář volá v akci create/update a podle módu modifikovat sestavení formuláře + naplnění dat.
Editoval m.brecher (24. 10. 2023 6:12)
- Kamil Valenta
- Člen | 822
m.brecher napsal(a):
Ještě je možné tam předat mód formuláře update/create podle toho zda se formulář volá v akci create/update a podle módu modifikovat sestavení formuláře + naplnění dat.
To není až tak nutno, vzhledem k tomu, že id je nullable…
- vosy
- Člen | 532
vyřešil bych to asi takto:
ve formuláři
private function formSucceeded(Form $form, $values)
{
.....
$form->reset();
$presenter->template->formContactInfoSuccessMessage = 'Your message has been send.';
}
a v template bych dal
{form contactForm action:"#".$Constants::ID_SECTION_CONTACT, class:$Constants::PREFIX.'-form'}
......
<div n:if="$form->ownErrors" class="alert alert-{$Constants::MSG_TYPE_ERROR} alert-flashing">
<ul>
<li n:foreach="$form->ownErrors as $error">{$error}</li>
</ul>
</div>
<div n:ifset="$formContactInfoSuccessMessage" class="alert alert-{$Constants::MSG_TYPE_SUCCESS} alert-flashing">
{$formContactInfoSuccessMessage}
</div>
{/form}
Je to velká prasárna?
- Marek Znojil
- Člen | 90
Tak si takové flash zprávy můžeš rozlišit dle druhého parametru.
$this->flashMessage('Email was sent successfully.', 'form');
Zprávy toho typu si vykrelíš jen poblíž toho formuláře. V obecném vykreslení je zase budeš ignorovat.
Jinak, první parametr může být i objekt. Takže si těch informací můžeš předat daleko více a v šabloně s tím pak různě pracovat.
- vosy
- Člen | 532
Marek Znojil napsal(a):
Tak si takové flash zprávy můžeš rozlišit dle druhého parametru.
$this->flashMessage('Email was sent successfully.', 'form');
Zprávy toho typu si vykrelíš jen poblíž toho formuláře. V obecném vykreslení je zase budeš ignorovat.
Jinak, první parametr může být i objekt. Takže si těch informací můžeš předat daleko více a v šabloně s tím pak různě pracovat.
No tak supeeeeeer, kde prosim najdu nejake povidani ohledne toho druheho
parametru a jak s nim pracovat?
Diiiiiiikes
- Kamil Valenta
- Člen | 822
Hm, já bych teda v druhém parametru očekával typ zprávy, tedy zda se
vykreslí např. zeleně, červeně, ve smyslu success/warning/danger. Ani ve
snu by mě nenapadlo, že se tím ovlivní i pozice a fakt, že šablona na
základě toho někde zprávu přeskočí.
Pokud chceš zprávu poblíž formu, proč prostě nedáš ten form do
komponenty? Protože komponenty mají svůj prostor flash zpráv a vykreslují
je u sebe.
Nevynalézat kolo má dvě výhody. Jednak ušetříš čas. A hlavně, když
to po Tobě někdo převezme, bude hned vědět kde co jak je. Takhle bude
hodně hledat, protože ho ty nestandardní postupy nenapadnou…