Existuje u formuláře něco jako $form->addSuccess(‚Email was sent successfully.‘);

vosy
Člen | 525
+
0
-

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 | 762
+
0
-

@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 | 762
+
+1
-

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 | 525
+
-3
-

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?

dakur
Člen | 493
+
+1
-

Je to velká prasárna?

Nejde ani tak o to, jestli je to prasárna, ale spíš čeho se snažíš docílit. Nevyhovuje ti z nějakého důvodu standardní řešení přes flash message?

vosy
Člen | 525
+
0
-

No přes flash message bych rád zobrazoval všeobecné zprávy, ale v tomto případě chci zobrazit zprávu poblíž formuláře.

Marek Znojil
Člen | 77
+
+3
-

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 | 525
+
0
-

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 | 762
+
0
-

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…

Kcko
Člen | 465
+
0
-

Souhlas s @KamilValenta , případně použij alespoň o trošku čistčí řešení něco jako

<?php
	$flash = $this->flashMessage('message ...', 'success');
	$flash->identifier = 'form';
?>

Editoval Kcko (24. 10. 2023 9:34)

Ozzrel
Generous Backer | 51
+
0
-

Mě přijde divný proč to má řešit formulář. Ten nic neví o tom jak to dopadlo a navíc se to stejně po úspěšném odeslání/zpracování někam přesměruje tak uživatel pozná, že se něco děje. A tam je spousta času vyvolat flashmessage.