Bootstrap modal + Nette form (+Naja)

Šaman
Člen | 2599
+
0
-

Ahoj, používám Bootstrap modal pro zobrazení formuláře v modálním okně. Ale po odeslání nechci ihned zavřít modal, protože formulář může být odeslaný chybně (serverová validace). Takže na submit tlačítku nemám navěšený JS pro zavření modalu. Používám snippety, takže s vypsáním validačních chyb není problém – překreslím jen ten formulář.

Mohu ale nějak zařídit zavření modalu až na základě zpracování formuláře?
Po úspěšném pracování překresluji celou stránku – flashmessage vyskočí, přesto mi zůstane celá stránka zašedlá a nelze na ni klikat (jako kdyby přes ni bylo modální okno, které ale není zobrazené). Pomohlo až vytvořit snippet v samotném tagu <body n:snippet="body">. Což není úplně košer – raději bych překreslil jen flasmessage a modal. Imho zapnutí modalu změnilo nějaké atributy přímo na <body> a pouhé překreslení modalu ho sice skrylo, ale ty změny na <body> zůstaly.

Máte nějaký osvědčený způsob, jak zpracovat Nette formulář v BS modalu tak, že zavření modálního okna zařídí překreslení snippetu?

Díky.

P.S. Používám Naju, ale v tomto se používá jen pro snippety. Modal je na ní zcela nezávislý.

Editoval Šaman (28. 1. 2021 8:06)

lookass
Člen | 50
+
0
-

Ahoj, vím, že se ptáš na Naju, ale nikdo nereagoval, tak bych si dovolil napsat, že Nittro tohle umí. Návod i příklad je na Nittro fóru

medhi
Generous Backer | 249
+
+3
-

Ahoj, stačí po úspěšném zpracování formuláře poslat $this->payload->closeModal = true; a do svého JS si dopsat toto zpracování, které modal zavře:

naja.addEventListener('success', event => {
	if (typeof event.detail.payload.closeModal !== 'undefined') {
		$('#myModal').modal('hide');
	}
});

Píšu to z hlavy, tak dej vědět, kdyby to nešlo, ale snad je jasný princip.

monty
Člen | 66
+
0
-

Ahoj.
Prosím pěkně, nedaří se mi zachytit Najou odeslání formuláře ve vyskakovacím modalu (dokresleným taktéž ve snippetu přes ajax).

// Přesedlal jsem z nette.ajax knihovny, kde jsem po vykreslení modalu volal...
$.nette.load();
naja.initialize(); // Mi vyhodí exception.

//Zkusil jsem teda naprasáka...
delete naja.initialized; //...ale to se rozbije uplně všechno :c)

Díky za radu :)

Šaman
Člen | 2599
+
0
-

Já to mám ještě rozkopaný, pak jsem chtěl dát na GitHub celou ukázku projektu. Ale jestli myslíš ajaxové odeslání formuláře, pro to jsem nic dělat nemusel. Mám Naju 2 a v základu jediné co potřebuji je

document.addEventListener('DOMContentLoaded', () => naja.initialize());

O chlup slozitější bylo až ovládání toho modal okna.

jiri.pudil
Nette Blogger | 1012
+
+1
-

Naja se na .ajax elementy v překreslených snippetech znovu-navěšuje sama, není potřeba nic volat. Pokud ale otevíráš modal nějakým javascriptem, je možné, že to v DOMu vyrobí nové elementy, o kterých Naja neví. V takovém případě budeš muset ajaxové chování navěsit ručně.

monty
Člen | 66
+
0
-

Paráda, moc děkuju! Tohle jsem v dokumentaci nepostřehnul :)

Pepino
Člen | 183
+
0
-

@vb76 Muzes v payloadu po uspesnem zpracovani formulare poslat napr closeModal=true a poladit si prekresleni snippetu https://naja.js.org/#…

Editoval Pepino (4. 4. 19:56)

vb76
Člen | 13
+
0
-

Pepino napsal(a):

@vb76 Muzes v payloadu po uspesnem zpracovani formulare poslat napr closeModal=true a poladit si prekresleni snippetu https://naja.js.org/#…

Jde mi spíše přímo o toto:

Ale po odeslání nechci ihned zavřít modal, protože formulář může být odeslaný chybně (serverová validace).

Pokud dojde k chybě, kterou předám přes $form->addError modal se po odeslání zavře. Když ho znovu otevřu, je formulář vyplněný, chyba zobrazena. Ale já nechci, aby se zavíral, když obsahuje info o chybě.

Hledám nějaké info, jak zamezit zavíraní modalu, když je zobrazena nějaká chyba. Pokud vše proběhne v pořádku, modal se zavře a obsah inputů vymaže. To je žádoucí a to mám vyřešené.

Pepino
Člen | 183
+
0
-

@vb76 zpracovavas ten formular v modalu ajaxem?

vb76
Člen | 13
+
0
-

Pepino napsal(a):

@vb76 zpracovavas ten formular v modalu ajaxem?

V modalu na form mám třídu ajax. Na formulář je vytvořena továrna a je v BasePresenter. Jedná se o registrační formulář, který je možné zobrazit na jakékoliv stránce.

Nicméně se to chová podobně i bez ajaxu, pokud bych ho nechtěl použít. Potřebuji asi jen nakopnout, jakým směrem jít. Třeba ověřuji e-mail na chybném místě v nesprávnou dobu. Takhle to mám zažité, ale modal pro formuláře používám poprvé.

Ve zpracování formuláře, po úspěšné validaci, ověřuji e-mailovou adresu v databázi. Pokud existuje, nastavím $form->addError().

		$form->onSuccess[] = function (Form $form, \stdClass $data) use ($onSuccess): void
		{
			if($this->user->checkEmail($data->iEmail))
			{
				$form->addError('E-mailová adresa již v systému existuje!');
			}
			else
			{
				$this->user->add($data);
			}
			$onSuccess();
		};

Formulář se odešle, modal zavře, ale obsahuje info z $form->addError(‚E-mailová adresa již v systému existuje!‘); Poku formulář znovu otevřu, je vše správně, ale já nechci, aby se zavíral, pokud obsahuje chybu. Potřebuji tomu nějak zamezit a vůbec netuším kde hledat, jakým směrem jít.

Editoval vb76 (4. 4. 21:50)

Pepino
Člen | 183
+
+2
-

@vb76 třídu ajax tam mít můžeš, ale otázka jestli se ti formulář ajaxem zpracovává.

Ověření emailu dej přímo na políčko iEmail.

$form->addEmail('iEmail')
	->addRule(function($control) {
		return $this->user->checkEmail($control->value)
	}, 'E-mailová adresa již v systému existuje!')
vb76
Člen | 13
+
0
-

Pepino napsal(a):

@vb76 třídu ajax tam mít můžeš, ale otázka jestli se ti formulář ajaxem zpracovává.

Ověření emailu dej přímo na políčko iEmail.

$form->addEmail('iEmail')
	->addRule(function($control) {
		return $this->user->checkEmail($control->value)
	}, 'E-mailová adresa již v systému existuje!')

Děkuji za TIP. Nicméně to problém se zavíráním modalu nevyřešilo. Toto pravidlo se stejně zavolá až po odeslání formuláře. To znamená, že bez ajaxu se problém nepodaří vyřešit…

Původně jsem si myslel, že se nejprve provedou javascriptová pravidla na straně klienta, pak se zpracuje onValidate a až pak se odešle formulář a zpracuje se onSuccess.

Pepino
Člen | 183
+
0
-

@vb76 pokud nebudeš ten formulář zpracovávat ajaxem tak se ti vždycky ten modal zavře.

Ano první se provedou javascriptová pravidla, pokud jsou v pořádku formulář se odesílá a přechází se k serverové validaci. Pokud serverová validace projde přechází se k onSuccess. Ale tady jsme opět u toho. Pokud nezpracováváš ajaxem tak javascript prostě neověří jestli zadaný email už existuje nebo ne.

m.brecher
Generous Backer | 263
+
0
-

@Šaman Ahoj, chtěl sjem se optat, zda Jsi nakonec dal na Github to řešení Bootstrap modal okna, které se zavře na základě zpracování formuláře na server, popř. rovnou odkaz, díky.

Petr Parolek
Člen | 443
+
0
-

@mbrecher tady je ukázka https://github.com/…test-project .

Petr Parolek
Člen | 443
+
0
-

Petr Parolek napsal(a):

@mbrecher tady je ukázka https://github.com/…test-project .

Ahoj, nevíte, jak prosím upravit kod, aby v odkazu Launch edit form in modal nebyl parametr isModal?

Pepino
Člen | 183
+
-1
-

Petr Parolek napsal(a):

Petr Parolek napsal(a):

@mbrecher tady je ukázka https://github.com/…test-project .

Ahoj, nevíte, jak prosím upravit kod, aby v odkazu Launch edit form in modal nebyl parametr isModal?

HomepagePresenter.php

Tohle smaž:

public function beforeRender(): void
{
	if ($this->isAjax() && (bool) $this->getParameter('isModal')) {
		bdump('isAjax');
		$this->payload->showModal = true;
		$this->payload->modalId = 'myModal';
		$this->redrawControl('modal');
	}
}

Tohle přidej:

public function actionEdit(): void
{
	if ($this->isAjax()) {
		$this->payload->showModal = true;
		$this->payload->modalId = 'myModal';
		$this->redrawControl('modal');
	}
}
Petr Parolek
Člen | 443
+
0
-

@Pepino nefunguje dobře modal se zavře, ale nezmizi v html:

<div class="modal-backdrop fade show"></div>

takže stránka zůstává napůl průhledná a stránku nelze ovládat.

Přikládám diff dle tvé rady:

diff --git a/app/Presenters/HomepagePresenter.php b/app/Presenters/HomepagePresenter.php
index ca3e969..e428162 100644
--- a/app/Presenters/HomepagePresenter.php
+++ b/app/Presenters/HomepagePresenter.php
@@ -15,10 +15,9 @@ final class HomepagePresenter extends Presenter
 	 */
 	public $database;

-	public function beforeRender(): void
+	public function actionEdit(): void
 	{
-		if ($this->isAjax() && (bool) $this->getParameter('isModal')) {
-			bdump('isAjax');
+		if ($this->isAjax()) {
 			$this->payload->showModal = true;
 			$this->payload->modalId = 'myModal';
 			$this->redrawControl('modal');
@@ -33,9 +32,7 @@ final class HomepagePresenter extends Presenter

 		$form->addSubmit('ok', 'OK');

-		$isModal = (bool) $this->getPresenter()->getParameter('isModal');
-
-		if ($isModal && $this->getPresenter()->isAjax()) {
+		if ($this->getPresenter()->isAjax()) {
 			$form->getElementPrototype()->class('ajax');
 		}

diff --git a/app/Presenters/templates/Homepage/default.latte b/app/Presenters/templates/Homepage/default.latte
index cafbb11..11c5acd 100644
--- a/app/Presenters/templates/Homepage/default.latte
+++ b/app/Presenters/templates/Homepage/default.latte
@@ -8,7 +8,7 @@
     {control itemsForm}
 {/snippet}

-<a n:href="Homepage:edit, isModal => 1" class="btn btn-outline-info ajax">Launch edit form in modal</a>
+<a n:href="Homepage:edit" class="btn btn-outline-info ajax">Launch edit form in modal</a>
 <!-- Button trigger modal -->
 <button type="button" class="btn btn-outline-info" data-toggle="modal" data-target="#exampleModal">
     Launch demo modal

Editoval Petr Parolek (29. 9. 13:55)

Petr Parolek
Člen | 443
+
0
-

@Pepino není potřeba upravit JS?

Editoval Petr Parolek (29. 9. 13:55)

Pepino
Člen | 183
+
0
-

@PetrParolek nezkoušel jsem to. Co to teď dělá? Po kliku na to tlačítko se otevře modál? Po odeslání formuláře se neschová?

if (showModal === undefined || showModal === false) {
	$("#" + modalId).modal('hide');
		return;
	}
}
Petr Parolek
Člen | 443
+
0
-

@Pepino schová, ale stále ne úplně viz obrázek https://ctrlv.cz/BpXB

Editoval Petr Parolek (29. 9. 16:53)

Petr Parolek
Člen | 443
+
0
-

@Pepino podařilo se ti něco vykoumat prosím?

Pepino
Člen | 183
+
0
-

@PetrParolek


	openModal(event) {
		let payload = event.detail.payload;

		if (payload === null || !payload.hasOwnProperty('modalId')) {
			return;
		}
		let modalId = payload.modalId;
		let showModal = payload.showModal;
		if (showModal === undefined || showModal === false) {
			$(".modal-backdrop").remove();
			$('body').removeClass('modal-open').removeAttr('style');
			return;
		}

		if ($(".modal-backdrop").length > 0) {
			$(".modal-backdrop").remove();
			$('body').removeClass('modal-open').removeAttr('style');
		}

		$("#" + modalId).modal('show');
	}

A v HomepagePresenter.php
createComponentTestForm
tohle

if ($isModal && $this->getPresenter()->isAjax()) {
	$form->getElementPrototype()->class('ajax');
}

nahradit tímhle

if ($this->getPresenter()->isAjax()) {
	$form->getElementPrototype()->class('ajax');
}

Editoval Pepino (29. 9. 18:09)

Petr Parolek
Člen | 443
+
0
-

Díky moc, funguje, jak má, ikdyž se mi zdá kod prasácký v JS, ale asi to jinak nejde https://github.com/…03f527d57d6e . Taky jsem měl rozepsané stejné řešení, ale stále jsem doufal, že půjde použít nějak $("#" + modalId).modal('hide');

Editoval Petr Parolek (29. 9. 18:44)

Pepino
Člen | 183
+
0
-

@PetrParolek Jinak to nejspíše nejde. Já mám svoje řešení trošku jiné ale (bs5, odstraněný neduh problíkávání) ale taky to není podle mě úplně čisté. Problém tam je v tom, že když se překreslí snippet s modalem, tak ztratí modal ztratí info o tom, že je vykreslený a nejde tím pádem použít modal('hide'). U mojeho řešení ho sice používám, ale je potřeba “ručně” modalu říct, že je vykreslený a inicializovaný. Jestli budeš chtít tak to tu postnu.

Petr Parolek
Člen | 443
+
+1
-

Můžeš kod aplikovat na mé demo s BS 5 prosím a poslat pull request? Díky.

Petr Parolek
Člen | 443
+
0
-

Napadlo mě udělat něco takového:

<a data-href="{link Homepage:edit, isModal => 1}" n:href="Homepage:edit" class="btn btn-outline-info ajax ajax-href">Launch edit form in modal</a>

Ale nevím, jak upravit JS, aby nebral odkaz z href ale z data-href-

Pepino
Člen | 183
+
0
-

Petr Parolek napsal(a):

Můžeš kod aplikovat na mé demo s BS 5 prosím a poslat pull request? Díky.

Je to tam.

Petr Parolek
Člen | 443
+
0
-

@Pepino ještě jednou díky, moc jsi mi pomohl – https://github.com/…oject/pull/2 , toto řešení je pecka.

Pepino
Člen | 183
+
0
-

@PetrParolek https://github.com/…oject/pull/3 tohle je muj PR