Editace položky přes formulář v modálním okně + ajax

hancs
Člen | 57
+
+2
-

Ahoj,
potřeboval bych poradit jakým způsobem vyřešit editační formulář v modálním okně pomocí ajaxu.
Mám stránku, na které mám v tabulce výpis položek. Už mi funguje přidání nové položky ajaxem v modálním okně, ale ještě potřebuji vyřešit jak na editaci. U každé položky mám tlačítko a po jeho stisknutí bych chtěl aby mi vyskočilo modální okno s formulářem pro úpravu a poté uložení pomocí ajaxu.
Potřeboval bych nějaký nástin, jak na to jít, protože nechci rovnou generovat modální okna se všemi formuláři. Nevím tedy jestli použít componentu, nebo dynamické snippety. A hlavně jakým způsobem to použít, aby to bylo čisté.
Předem moc díky, za jakýkoliv nástin, jak to vyřešit.

Jan Mikeš
Člen | 771
+
+6
-

Ahoj, mohu se s tebou podelit o reseni, ktere pouzivam ja, je docela prijemne a pro rozsireni jiz existujiciho reseni vyzaduje jen minimum psani a zajaxovani existujici admin se da udelat behem par minut.

Reseni pouziva Twitter Bootstrap 3 modals a nette.ajax.js

Hlavni @layout.latte (uplne nakonci stranky, prakticky tesne nad </body>):

{snippet modal}
		{if $presenter->isAjax()}
			{ifset #modal}
				<div class="modal fade modal-ajax">
					<div class="modal-dialog">
						<div class="modal-content">
							<div class="modal-header">
								<button type="button" class="close" data-dismiss="modal">&times;</button>
								{block modalHeader}
									<h3 class="modal-title">
										{block|striptags}{include #title}{/block}
									</h3>
								{/block}
							</div>
							<div class="modal-body">
								{include #modal}
							</div>
							{ifset #modalFooter}
								<div class="modal-footer">
									{include #modalFooter}
								</div>
							{/ifset}
						</div>
					</div>
				</div>
			{/ifset}
		{/if}
	{/snippet}

Asi netreba mnoho komentare, jsou k dispozici 3 bloky #modalHeader, #modal a #modalFooter, ktere ti umozni menit obsah (ja osobne pouzivam jen #modal, kdyz se kouknes na vychozi vzhled #modalHeader, tak pokud jej neprepises tak se vlozi block #title, coz mi ve vetsine pripadech staci)

Nasleduji extensions pro nette.ajax.js:

<script>
	$.nette.ext("modals", {
		success: function(payload) {
			if (payload.redirect) {
				$(".modal-ajax").modal("hide");
			} else if(payload.isModal) {
				$('.modal-ajax').modal('show');
			}
		}
	});

	$.nette.ext("ajaxRedirect", {
		success: function (payload) {
			if (payload.redirect) {
				$.nette.ajax(payload.redirect);
			}
		}
	});
</script>

modals extension se stara o otevreni modalniho okna pokud je v payloadu parametr isModal nastaven na true (viz nize), ajaxRedirect se stara o plne zajaxovani aplikace, aby se pri redirectech nerefreshovala stranka (tusim ze ve vychozim stavu nette.ajax.js je toto chovani).

Editacni presenter:

	public function actionAdd()
	{
		if ($this->isAjax()) {
			$this->payload->isModal = TRUE;
			$this->redrawControl("modal");
		}
	}


	public function actionEdit($id)
	{
		// my application logic, entity fetch etc..., redirect if not existing

		$this["manageForm"]->setDefaults($this->entity->toArray());

		if ($this->isAjax()) {
			$this->payload->isModal = TRUE;
			$this->redrawControl("modal");
		}
	}

Pouzivam formulare v modalech jak pro pridavani, tak editaci, navic pouzivam stejny formular pro pridavani i editaci.

Sablona presenteru s editaci:

{block title}Editovat xyz{/block}

{block content}
<p class="buttons">
	<a class="btn btn-primary" n:href="default">
		<i class="fa fa-chevron-left"></i>
	</a>
</p>

{block modal}
	{control manageForm}
{/block}

Reseni je opravdu jednoduche ;) Ja k tomu vyuzivam traity a automaticky generovane formulare podle entit, cely muj presenter pak vypada napr takto (pomoci preddefinovanych sablon je tedy vygenerovani admin k 1 cele sekci otazka ani ne 2 minut):

<?php

namespace App\AdminModule;

use Lexinek\PresenterHandlers\Deletable\Handler as DeletableHandler;
use Lexinek\PresenterHandlers\ManageActions;

final class SizeTablePresenter extends SecuredPresenter
{
	use DeletableHandler;
	use ManageActions;


	protected function startup()
	{
		parent::startup();

		$this->addViewTitle = "Přidat tabulku velikostí";
		$this->editViewTitle = "Editovat tabulku velikostí";
	}
}

Zajaxovani a otevreni modalu ve tvem seznamu zaznamu je jenom o pridani class="ajax" na odkaz.

Edit: jeste bych rad podotknul, ze toto reseni povazuji za ciste, protoze funguje i bez ajaxu (pri otevreni noveho tabu) a neprobiha prednacitani zadnych dat na pozadi, data se opravdu nacitaji az po kliku na tlacitko editovat/pridat

Editoval Lexi (21. 6. 2016 19:26)

lalo
Člen | 26
+
0
-

Ahoj, prosimte, a jak z takoveho modalu invalidujes snipety v sablone, ze ktere modal volas?

default.latte

<a class="btn btn-primary" n:href="add">Add</a>

{snippet novaHodnota}
ve formulari v modalu jste zadali: {$hodnota}
{/snippet}
Jan Mikeš
Člen | 771
+
0
-

Ahoj, klasicky v renderDefault():

public function renderDefault()
	{
		$this->template->items = $this->em->getRepository($this->getEntityClassName())->findBy($this->findBy, $this->orderBy);

		if ($this->isAjax()) {
			$this->redrawControl("list");
		}
	}
{snippet list}
	{foreach $items as $item}
		...
	{/foreach}
{/snippet}
lalo
Člen | 26
+
0
-

Jo dekuji,
chyba byla jinde. Zaclo mi to fungovat az pote co jsem prilinkoval history.ajax

Pozor, v uvedenem kodu je chyba:
$(".ajax-modal").modal("hide");

ma byt
$(".modal-ajax").modal("hide");

Editoval lalo (11. 6. 2016 6:58)

lalo
Člen | 26
+
0
-

@Lexi Prosim o pomoc, stale se mi nedari tvuj priklad rozchodit.

Mam li v modalnim okne formular, musim tento po odeslani presmerovat na Default stranku presenteru, abych mohl prekreslit snippet, kvuli kteremu jsem modalni okno volal, k tomu je zrejme v js

$.nette.ajax(payload.redirect);

jenze to mi nikdy neprojde ajaxove, at uz nastavim formulari

public function _submit($form) {
	$form->presenter->flashMessage("Vaše data byla úspěšně uložena", "success");
	$form->presenter->redirect("default");
};

nebo

public function _submit($form) {
	$form->presenter->flashMessage("Vaše data byla úspěšně uložena", "success");
	$form->presenter->payload->redirect = $form->presenter->link('Homepage:default');
};

funguje to jen pokud pridam extension history.ajax

A take pokud formular validuje hodnoty a nektera z nich validaci neprojde,

$form->onValidate[] = [$this, 'validateValues'];

prekresli se formular v modalnim okne a zobrazi se chybove hlaseni, coz je spravne, ale zavola se take znovu

$('.modal-ajax').modal('show');

ktery zrejme posle druhy fade efekt, diky cemuz, uz nejde se strankou pracovat.

na formulari mam standartne pridanou tridu ajax

protected function createComponentManageForm() {
	$form = new \Nette\Application\UI\Form;
    $form->getElementPrototype()->class[] = 'ajax';
	$form->addSubmit('submit', 'Submit')
                ->setAttribute('class', 'ajax');
	$form->onValidate[] = [$this, 'validateValues'];
	$form->onSuccess[] = [$this, '_submit'];
	return $form;
}

Dokazes prosim rict, kde by mohla byt chyba? Pouzivam nette.ajax.js z gitu.

Jan Mikeš
Člen | 771
+
0
-

Ahoj, koukni se do sveho nette.ajax.js a hledej extension redirect → https://github.com/…ette.ajax.js#L479 je v originalnim scriptu, ta zpusobuje prave to, ze pokud namisto ajaxoveho pozadavku na novou url se redirectne. U me osobne je tato extension nezadouci, takze ji nepouzivam. K validation ti zkusim poradit jeste pozdeji, udelam par testu.

lalo
Člen | 26
+
+1
-

@Lexi takze ten problem s prekreslovanim modalu po neuspesne validaci formulare jsem vyresil.
vyhodil jsem ze sablony vsechny casti kodu, ktere includujes {include #modal} a nahradil je jedinym snippetem (komponentou modal), ktery invaliduji. (ty include vkladaly za sebe porad dalsi formulare)

a js script jsem upravil tak, aby nejdrive vycistil vsechny zbytky modal okna a pak ho ciste otevrel

$.nette.ext("modals", {
    success: function (payload) {
        if (payload.redirect) {
            $(".modal-ajax").modal("hide");
        } else if (payload.isModal) {
            $("body.modal-open").removeAttr("style");
            $('body').removeClass('modal-open');
            $('.modal-backdrop').remove();
            $('.modal-ajax').modal('show');
        }
    }
});
walda
Člen | 5
+
0
-

Ahoj @Lexi,
díky za super řešení hodně jsem se inspiroval. Jen bych se tě chtěl zeptat jak řešíš když by jsi potřeboval na jedné stránce třeba dva formuláře v modalu. Děkuji za radu.

Jan Mikeš
Člen | 771
+
0
-

@walda jak to myslíš? 2 formuláře najednou v jednom otevřeném modalu? Zatím jsem takovou situaci neměl, ale řešil bych to například tabama přímo v tom modalovém okně (v šabloně v {block modal}). Případně zkus blíže popsat co potřebuješ vyřešit a najdeme optimální řešení.

walda
Člen | 5
+
0
-

@Lexi Myslím to tak že mám například, šablonu detail.latte v ní mám první modal pro editaci vytvořen pomící řešení víše, viž:

{define modal}
	{control myForm}
{/define}

a ve stejné šabloně detail.latte byl potřeboval ještě nadefinovat jedno modalní okno s formulářem tudíš:

{define modal}
	{control myForm2}
{/define}

problém nastává v tom že logicky nemůžu v jedný šabloně použít dvakrát {define modal}. Ne víš jak ten to problém vyřešit nějak správně a čistě? Díky moc.

Jan Mikeš
Člen | 771
+
0
-

Jakého charakteru jsou ty formuláře? Napadají mě 3 řešení, podle toho jakou spojitost spolu ty formuláře mají:

  1. Rozdělit do 2 šablon
  2. Mít to v jednom modalu a rozdělit např. pomocí tabů
  3. Jedna šablona, vytvořit si pomocný parametr a v {block modal} vypisovat najednou vždy pouze jeden formulář {if $modal === 1}{elseIf $modal == 2}{/if} a pak odkazovat <a n:href="something, modal=>2">
unnamedno.21
Člen | 1
+
0
-

Zapojím sa do tohoto vlákna s pár otázkami k rovnakej problematike – AJAX formulár ako komponenta v modále.
Moje riešenie, ktoré aktuálne mám mi príde celkom neohrabané a rád by som k tomu pristupoval nejak rozumnejšie.
Moje otázky:

  1. Ako ideálne-najpohodlnejšie riešit komponentu ktorá sa má vykresliť v modále ?
  2. Ajaxový požiadavok ktorý iniciiuje vykreslenie formulára má smerovať do handle / action ? Aký je v tomto prípade rozdiel ?
  3. Do komponenty formulára mám posielať len $id a obsah vytiahnuť v komponente, alebo posielať priamo objekty a komponenta pracuje len s ich obsahom ?
  4. Po odoslaní formulára sa znova vykonáva actionDefault a konštruktor komponenty – tento workflow nie celkom rozumiem a je to vlastne môj hlavný problém pri danej AJAX komponente.
  5. Defaultné vlastnosti formulára mám nastavovať v komponente pri jednotlivých fieldoch, alebo z presentra this[‚form‘]→ atď. Je v tomto prípade nejaký rozdiel ?
  6. FormSucceed prebieha ako samostatný požiadavok, takže property danej komponenty ktoré som si prebral v konštruktore vo FormSucceed neexistujú (či už objekt, alebo len id) – ako sa k nim dostanem ? Je správny prístup ukladanie do hidden fieldov ?
  7. Celé by som to zaobalil prosbou o vysvetlenie správneho prístupu k danej problematike.

Ďakujem

Aktuálne riešenie v kóde:

Presenter

<?php

public $myObject;
public $showModal;

actioDefault()
{
	// nasledujuci kód som pridal, aby sa úspešne vykonal POST formulára - je tento prístup správny ?
	$id = $this->getParameter("id");
    if ($id != NULL)
		$this->myObject= $this->myRepo->find($id);

	... some logic
}

renderDefault()
{
	if(this->showModal)
	{
		this->template->editModal = true;
	}
}

handleEdit($id)
{
	this->myObject = this->myRepo->find($id);
	this->showModal = true;
	this->redrawControl("showEditForm");
}

protected function createComponentEditForm()
{
	$form = $this->factory->create($this->myObject);
	return $form;
}
?>

Šablona Presentra

<?php

<a class="ajax" href="{link edit! $someObjectInTemplate->id}">

{snippet showEditForm}
	{if $editModal === true}
		{control editForm}
	{/if}
{/snippet}
?>

Komponenta (vytváraná cez factory)

<?php
private $object;
private $subObject;

public function __construct($myObject)
{
	parent::__construct();
	this->object = $myObject;
	this->subObject = this->object->subObject; // pod odoslani formu kod spadne na trying to get property of non object, neuspesny POST
}

public function render()
{
	this->subObject = this->object->subObject; // ked presuniem kod do render, form sa uspesne odosle
}

public function createComponentEditForm($name)
{
	$form = new Form();
    $this[$name] = $form;

	$form->addText('txtfield1', 'Text1')
		->setDefaultValue(this->object->text)

	$form->addText('txtfield2', 'Text2')
		->setDefaultValue(this->subObject ->text)

	$form->addSubmit('save', 'Ulozit');
    $form->onSuccess[] = [$this, 'formSucceeded'];

	return $form;
}

public function formSucceeded(Form $form, $values)
{
	// spracovanie formulara
}

?>

Šablona komponenty

<?php
{form editForm class => 'ajax'}
	// form fields
{/form}
?>
jarda256
Člen | 130
+
0
-

@JanMikeš Ahoj, používám tvoje řešení a je fakt super. Akorát jsem narazil na problém, se kterým si nevím rady. V modalu mám formulář se selectem a chtěl bych v závislosti na zvolené položce selectu překreslit snippet itemDetail. Nejlépe co se mi podařilo, tak se modal zavřel a otevřel s detailem, ale zůstalo ztmavení pozadí z předchozího. Ideálně bych potřeboval aby se překresil pouze detail a modal zůstal otevřen. Lze to vůbec?

{block content}
	<div id="banner">
		<h1 n:block=title>{_ ui.registrationAddOptItems.title}</h1>
	</div>
	{block modal}
		<div class="row">
			<div class="col-sm-6">
				<form n:name=addOptItemForm class="form-horizontal">
					{input regId}
					<div class="form-group">
						<div class="col-sm-3 control-label">{label item /}</div>
						<div class="col-sm-9">{input item}</div>
					</div>
					<div class="form-group">
						<div class="col-sm-3 control-label">{label count /}</div>
						<div class="col-sm-9">{input count}</div>
					</div>
					<div class="form-group">
					</div>
					{input send}
				</form>
			</div>
			<div class="col-sm-6">
				{snippet itemBox}
					{ifset $itemDetail}
						<div class="row">
							<div class="col-sm-6">
								<h6><b>Název: </b>{$itemDetail->name}</h6>
								<h6><b>price: </b>{$itemDetail->price}</h6>
								<h6><b>pricee: </b>{$itemDetail->eprice}</h6>
							</div>
							<div class="col-sm-3">
								<img src="/upload/optItems/{$itemDetail->picture->name}" class="img-responsive">
							</div>
						</div>
					{/ifset}
				{/snippet}</div>
		</div>
		<script>
			$('select[name=item]').change(function () {
				$.nette.ajax({
					url: {link getDetail!},
					data: {
						'value': $('select[name=item]').val(),
					}
				});
			});
		</script>
	{/block}
{/block}
	public function handleGetDetail($value) {
		$itemDetail = $this->optItemFacade->getOptItem($value);
		$this->template->itemDetail = $itemDetail;
		if ($this->isAjax()) {
			$this->redrawControl('itemBox');
		}
	}
Jan Mikeš
Člen | 771
+
0
-

ahoj @jarda256 jsem rád, že se ti řešení líbí. V posledním projektu, kde jsem jej používal, jsem to vyřešil následovně (upravená extension pro modaly):

	$.nette.ext("modals", {
		success: function(payload) {
			if (payload.redirect) {
				$(".modal-ajax").modal("hide");
			} else if(payload.isModal) {
				$(".modal-backdrop").remove(); // Tento řádek je zde nový
				$('.modal-ajax').modal('show');
			}
		}
	});

To chování co popisuješ při vyvolání modalu z modalu (starý se zavře, nový se otevře) tam mám také, uživatelům administrátorského rozhraní to nevadilo, takže jsem to neřešil a nechal to tak jak popisuješ, akorát s opravenou chybou při nemiznutí předchozího overlaye (viz kód výše).

Věřím ale, že by se to zavírání+otevírání dalo pár řádky ošetřit – chtělo by to v js kontrolovat, jestli je otevřený modal a zároveň další ajax request se otevírá v modalu, v tom případě pouze překreslit modaly a nevyvolávat další modal, zkusím otestovat a pokud se mi povede, pošlu sem funkční kód.

Jan Mikeš
Člen | 771
+
0
-

Po hodině experimentování jsem došel k tomuto kódu, který je plně funkční:

<script>
	$.nette.ext("modals", {
		before: function() {
			this.wasModalOpenedBeforeAjaxRequest = this.isModalOpened();
		},
        success: function(payload) {
            if (payload.isModal) {
            	if (!this.wasModalOpenedBeforeAjaxRequest) {
					$('.modal-ajax').modal('show');
				} else {
					$('.modal-ajax').addClass('in').css({'display': 'block'}).modal('show');
					$('.modal-backdrop').removeClass('fade');
					$('.modal-backdrop:not(:last)').remove();
					window.setTimeout(function() {
						$('.modal-backdrop').addClass('fade');
					}, 200);
				}
            } else {
                $('.modal-ajax').modal('hide');
            }
        }
    }, {
    	wasModalOpenedBeforeAjaxRequest: false,
    	isModalOpened: function() {
    		return ($('.modal.fade.in').length > 0);
		}
	});
</script>

Nahrál jsem i video, jak to v praxi funguje. Pro vysvětlení, kliknutí na křížek je další ajax request <a n:href="default" class="ajax">. Na videu jsou 2 situace – 1) otevřu modal a zavřu 2) otevřu modal a otevřu další modal kliknutím na link <a n:href="this" class="ajax">.

Javascript kód je trošku krkolomný kvůli tomu, že blikal backdrop, pak blikal modal, poté se nedařilo modal zavřít atd :-)).

Video s ukázkou v praxi

Editoval Jan Mikeš (5. 5. 2017 12:53)

jarda256
Člen | 130
+
0
-

@JanMikeš Ahoj, děkuju moc. Je to naprosto super. Ještě bych měl dotaz. Všimnul jsem si, že tam máš loader než se načte ten modal. Jak bych ho tam dostal?? :)

Edit: A když už se ptám. Jde udělat aby po úspěšném formuláři se modal pouze zavřel.

Editoval jarda256 (5. 5. 2017 17:40)

Jan Mikeš
Člen | 771
+
+1
-

Na progress používám plugin nprogress, extension do nette pak vypadá takto:

<script>
	$.nette.ext('nprogress',  {
        start: function() {
            window.NProgress.start();
        },
        complete: function() {
            window.NProgress.done();
        }
    });
</script>

Poté jsem si jen upravil css, o které se samozřejmě rád podělím:

<style>
#nprogress .spinner {
  display: block;
  position: fixed;
  z-index: 99999;
  top: 50%;
  right: 50%;
  width: 60px;
  height: 60px;
  border-radius: 20px;
  background: rgba(0, 0, 0, .5);
  margin-left: -30px;
  margin-top: -30px;
}

#nprogress .spinner-icon {
  width: 20px;
  height: 20px;
  box-sizing: border-box;

  border: solid 2px transparent;
  border-top-color: #fff;
  border-left-color: #fff;
  border-radius: 50%;
  display: inline-block;
  margin: 20px;

  -webkit-animation: nprogress-spinner 400ms linear infinite;
          animation: nprogress-spinner 400ms linear infinite;
}

.no-spinner #nprogress .spinner {
  display: none;
}

.nprogress-custom-parent {
  overflow: hidden;
  position: relative;
}

.nprogress-custom-parent #nprogress .spinner,
.nprogress-custom-parent #nprogress .bar {
  position: absolute;
}

@-webkit-keyframes nprogress-spinner {
  0%   { -webkit-transform: rotate(0deg); }
  100% { -webkit-transform: rotate(360deg); }
}
@keyframes nprogress-spinner {
  0%   { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
</style>

Co se týká pouze zavření modalu, to si řídíš v PHP, stačí nastavit $this->payload->isModal = FALSE; v presenteru a modal se zavře.

jarda256
Člen | 130
+
0
-

@JanMikeš takže submit musí mít class ajax a co je tu ještě potřeba? Neudělá se pomalý hide jako při klinutí mimo a zůstane pozadí. Dalo by se to nějak opravit?

	protected function createComponentAddGuestsAdminForm()
	{
		$form = new Nette\Application\UI\Form();
		$form->setRenderer(new BootstrapRenderer());
		$form->addInteger('guestCount', 'Pocet guestu')->setDefaultValue('0')
			->addRule(Nette\Application\UI\Form::MIN, 'Minimalne 0', 0);

		$form->addSubmit('send', 'potvrdit')->setAttribute('class', 'ajax');
		$form->onSuccess[] = [$this, 'addGuestsAdminFormSucceeded'];
		return $form;
	}

	public function addGuestsAdminFormSucceeded(Nette\Application\UI\Form $form, $values)
	{
		$this->registrationFacade->addGuestsToRegistrationAdmin($this->regId, $values);
		$this->payload->isModal = FALSE;
	}

EDIT: a když máš ten nprogress, tak co musíš udělat aby ti to fungovalo? Promiň blbé otázky. Jsem začátečník a ještě docela tápu

Editoval jarda256 (10. 5. 2017 21:59)

jarda256
Člen | 130
+
0
-

@JanMikeš Možná bys mi mohl ještě poradit? mám dva formSucceeded a u jednoho se po dokončení modal zavře ale u druhého ne. Tvrdí to že isModal je TRUE, ale přitom je tam nastaveno na false. Díky za rady

ten je ok

	public function identifyGuestsAdminFormSucceeded(Form $form, $values)
	{
		$this->checkFacade->identifyGuestAdmin($values, $this->guestId);
		$this->flashMessage('Guest identifikovan', 'success');
		$this->redrawControl('flashes');
		$this->redrawControl('modal');
		$this->checks = $this->checkFacade->getChecksByRegistrationIdQuery($this->regId);
		$this['basicDataGridChecks']->reload();
		$this->payload->isModal = FALSE;
	}

tenhle zůstane otevřený

	public function addMemberAdminFormSucceeded(Form $form, $values)
	{
		$team = $this->teamFacade->getTeam($values->teamId);
		$this->personFacade->createPersonAdmin($team, $values);
		$this->flashMessage('Clen pridan', 'success');
		$this->redrawControl('flashes');
		$this->redrawControl('modal');
		$this->people = $this->personFacade->getPeopleByTeamIdQuery($values->teamId);
		$this['detailDataGrid']->reload();
		$this->payload->isModal = FALSE;
	}
Jan Mikeš
Člen | 771
+
0
-

Chtělo by to odkrokovat, kde a proč se ta hodnota přepisuje (doporučuji xdebug, pokud neznáš a nepoužíváš, začni, je to totální killer všech chyb!).

Co se týká předchozích otázek s progressbarem atd. to jsi již vyřešil?

jarda256
Člen | 130
+
0
-

Progress jsem už vyřešil…v podstatě krokuju stejně akorát po schválení mi to hodí before a pak místo toho aby se mi hodilo isModal jako false, tak se hodi ze je true, ale nikde to neni…a nejake rady na integraci x debugu a co xdebug s php stormem

sibka
Člen | 24
+
0
-

@JanMikeš Ahoj, dnes jsem vyzkoušela Tvé řešení a vypadá super. Jen mi v modalu u formuláře nefungují vlastní validační pravidla. Pokud formulář vložím přímo do šablony a nezobrazím v modalu, je vše OK a chyby se objeví. U formuláře v modalu se mi sice vyhodnotí (dump ukazuje správný výsledek), ale modal se stejně zavře.
Required funguje, modal se nezavře, chyba se objeví. Jen ta vlastní validační pravidla jako callback v modalu zlobí. Nevíš, kde by mohl být problém?

Jan Mikeš
Člen | 771
+
0
-

@sibka ahoj, tuším, že problém bude s tím, že se ti neaplikují pravidla na nově přidaný element do DOM. Můžeš sem poslat ukázku javascriptu těch validačních pravidel? Já osobně používal live validation a přesně tento problém jsem vyřešil přes nette ajax extension:

<script>
$.nette.ext('initFormsValidation', {
		success: function(payload) {
			if (payload.snippets) {
				for (var snippetId in payload.snippets) {
					$("form", "#" + snippetId).each(function() {
						Nette.initForm(this);
					});
				}
			}
		}
	});
</script>
Mart78
Člen | 31
+
0
-

Můžete mě někdo nakopnout jakým způsobem získám ID při zpracování editačního formuláře? Tím že ho do modalu vykreslím přes ajax, tak nemám v URL ID položky, a tudíž pak při odeslání formuláře nemám možnost $this->getParemeter('id')

AdamVyborny
Člen | 36
+
0
-

Mart78 napsal(a):

Můžete mě někdo nakopnout jakým způsobem získám ID při zpracování editačního formuláře? Tím že ho do modalu vykreslím přes ajax, tak nemám v URL ID položky, a tudíž pak při odeslání formuláře nemám možnost $this->getParemeter('id')

Dej ho tomu handlu jako parametr např.

<?php
	/**
     * @param $offset
     */
    public function handleLoadMoreNotifications($offset)
    {
        $this->offset = $offset;
        $this->redrawControl('notifContainer');
    }
?>
d@rkWolf
Člen | 167
+
0
-

@JanMikeš Zdravím, zkoumal sem řešení modalů a tohle tvoje řešení mě zaujalo, protože tak nějak mě to zhruba napadlo, jen se mi to nedařilo dát dohromady, každopádně jsem narazil na problém, který se mi nedaří vyřešit.

Mám modal v akci „actionAddPopup“ v „SettingsPresenteru“, v něm mám vytvořenou komponentu formuláře do toho modalu, v default šabloně toho presenteru mám ve snippetu(popupList) tabulku položek, které se tím modalem přidávají a tlačítko add k otevření toho modalu, ale nedaří se mi tento snippet po odeslání formuláře v modalu překreslit.

V komponentě formuláře mám normálně:

<?php
public function popupFormSubmitted(Form $form) {

...zpracování...

$this->presenter->flashMessage('Popup úspěšně uložen!', 'alert-success');
if ($this->presenter->isAjax()) {
	$this->presenter->redrawControl('flashes');
	$this->presenter->redrawControl('modal');
	$this->presenter->redrawControl('popupList');
	$this->presenter->payload->closeModal = true;
	$this->presenter->payload->isModal = false;
}  else {
	$this->presenter->redirect('this');
}
?>

Po kliknutí na submit ve formu v modalu se data uloží, modal se zavře, zobrazí se mi flashes, ale ta tabulka v presenteru(snippet popupList) se nepřekleslí, nově přidaná položka se tam neobjeví, na tom musím dát F5 což je docela na houby. Když se podívám do toho, co se podívám do odesílané odpovědi, jsou tam obě proměnné v payloadu a 2 snippety(flashes a modal), 3.snippet popupList chybí. Nedaří se mi přijít na to, jak to správně zavolat, aby se to překreslilo také?

iNviNho
Člen | 352
+
0
-

Ak sa nemýlim, tak payloady musíš odosielať

<?php
$this->presenter->sendPayload();
?>

a v tom prípade neviem či ti pôjde redrawControl(), pretože nebudeš posielať nový HTML kód ale iba nejaká data – payload, alebo json

d@rkWolf
Člen | 167
+
0
-

iNviNho napsal(a):

Ak sa nemýlim, tak payloady musíš odosielať

<?php
$this->presenter->sendPayload();
?>

a v tom prípade neviem či ti pôjde redrawControl(), pretože nebudeš posielať nový HTML kód ale iba nejaká data – payload, alebo json

Ty payloady by měly být v pohodě, to funguje-oproti tomu JS od Jana Mikeše mi tam totiž nefunguje to „if (payload.redirect) {“, redirect v payloadu nemám(netuším proč, jako kdybych měl chování nette.ajax nějak obrácený), každopádně ajaxově se to provádí tak jak by mělo(nereloaduje se celý obsah), tak já sem si tam přidal speciálně ten closeModal, kterej mám v tom IF místo toho redirectu, abych věděl, že mi to zavřelo modal a odstranilo ten šedivej backdrop od Bootstrap Modalu a to funguje správně, modal se zavře, backdrop se odstraní.

Problém je, že z té komponenty v komponentě(je to vlastně vytvořená komponenta té editace a uvnitř je vytvořená komponenta samotného formuláře uvnitř toho modalu) se mi neobnoví obsah snippetu uvnitř presenteru(takže mi nepřibude do tabulky nově vložená položka z toho modalu) z kterého to volám(ale přitom se obnoví snippet flashes a snippet modal, kterej je v globálním @layout.latte). Obě ty proměnné co dávám do payloadu poslané mám, k tomu ty 2 snippety, třetí snippet to ignoruje.

Editoval d@rkWolf (31. 1. 2018 21:00)

jikki
Člen | 73
+
0
-

Ahoj,

@JanMikeš povedlo se mi zprovoznit tvé řešení, funguje dobře. Je tu však jedna věc, na kterou nemohu přijít jak udělat. A sice potřeboval bych vyskočit modal i při načtení celé stránky, tedy ne pouze při ajaxovém požadavku.

Poradil bys prosím tě?

Díky moc