addDynamic přehazuje pořadí prvků při použití ajaxu

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Filip111
Člen | 244
+
0
-

Ahoj, používám addDynamic pro komplikovanější formulář, kde je v jednom kontejneru vložen další. Přeloženo: v jednom kontejneru se zadávají dny,
ve vnořeném kontejneru se definují nějaké požadavky pro tento den, kterých může být libovolný počet.

Na formuláři jsou tlačítka pro přidání/odebrání dne a přidání/odebrání požadavků pro tento den.
Přidávání/odebírání dní funguje v pořádku, ale když přidám nový prvek do požadavků dne (vnořený kontejner), přehodí se pořadí definovaných dní. (Když pracuji s prvním dnem, tak nic, když pracují s jiným dnem, vždy se přesune jako první).

A pozor, děje se to pouze pokud jsou tlačítka zajaxována. Při normálním requestu sepořadí dní nezmění. Poradíte? (je to stěžejní formulář celé aplikace a už se s tím peru docela dlouho).

Díky.

ps.: Kódy jsem ořezal na minimum, děje se to stále (u plného i prázdného formuláře).

public function createComponentEditForm() {
		$form = new EditForm;
		$form->addText('title', 'Název', 80);
		$removeEvent = callback($this, 'MyFormRemoveElementClicked');
		$step = $this;
		$dates = $form->addDynamic('dates', function (\Nette\Forms\Container $date) use($removeEvent, $step) {
					$date->addText('date', 'Datum', 10)
							->getControlPrototype()->class('datepicker');
					$date->addHidden('id');
					$requirements = $date->addDynamic('reqs', function (\Nette\Forms\Container $req) use($removeEvent, $step) {
								$req->addSelect('job', 'Kvalifikace', $step->context->akce->jobsRepository->catalog());
								$req->addText('count', 'Počet', 5);
								$req->addSubmit('remove', 'smazat')
									->setValidationScope(FALSE) # zakáže validaci
									->onClick[] = $removeEvent;
							}, 0);
					$requirements->addSubmit('add', 'Přidat kvalifikaci')
							->setValidationScope(FALSE)
							->onClick[] = callback($step, 'MyFormAddElementClicked');

					$date->addSubmit('remove', 'Smazat datum')
							->setValidationScope(FALSE) # zakáže validaci
							->onClick[] = $removeEvent;
				}, 1);
		$dates->addSubmit('add', 'Přidat datum')
				->setValidationScope(FALSE)
				->onClick[] = callback($this, 'MyFormAddElementClicked');

		$form->addSubmit('save', 'Uložit akci')->setAttribute('class', 'default');
		$form->onSuccess[] = callback($this, 'editFormSuccess');
		return $form;
	}

Template:

{snippet datesForm}
	{form editForm}
<div class="tab-content">
	<div class="tab-pane" id="header">
		<div class="well">
		<table>
			<tr><td>{label title /}</td><td>{input title}</td></tr>
		</table>
		</div>
	</div>

	<div class="tab-pane active" id="dates">

	{foreach $form['dates']->containers as $id => $date}
	<div class="row-fluid">
		<div class="span4">
			<div class="control-group">
			<table>
				<tr><td>{label dates-$id-date /}</td><td>{input dates-$id-date} {input dates-$id-id}</td></tr>
			</table>
			</div>
		</div>
		<div class="span3">
			<table>
			{foreach $date['reqs']->containers as $rid => $req}
			<tr>
				<td>{label dates-$id-reqs-$rid-job /}</td>
				<td>{input dates-$id-reqs-$rid-job}</td>
				<td>{input dates-$id-reqs-$rid-count class => 'input-mini ajax'}</td>
				<td>{input dates-$id-reqs-$rid-remove, class => 'btn-mini ajax'}</td>
			</tr>
			{/foreach}
			<tr><td></td><td></td><td></td><td>{input dates-$id-reqs-add, class => 'btn-mini btn-info ajax'}</td></tr>
			</table>
		</div>
	</div>
	<div class="row-fluid"><div class="span1"></div></div>
	<div class="row-fluid">
		<div class="span8"></div>
		<div class="span2">{input dates-$id-remove, class => 'btn ajax'}</div>
		<div class="span1">{input dates-add, class => 'btn btn-success ajax'}</div>
	</div>
	{/foreach}

	</div>{*dates end*}

</div>{* tab-content end *}
<br />
{input cancel, class => 'btn'} {input save, class => 'btn btn-primary'}
{/form}
{/snippet}

U ajaxu nic speciálního nemám, jen inicializaci nového scriptu nette.ajax.js

$(function () {
	$.nette.init();
});
Filip Procházka
Moderator | 4668
+
0
-

Něco málo jsem tam předělal, ale nedaří se mi nasimulovat tu tvou chybu. Vyzkoušej tento sandbox. Pokud se ti to povede nasimulovat zde, tak pošli kompletní kód, třeba v zipu, ale na tomhle čistém sandboxu.

Editoval HosipLan (1. 9. 2012 1:52)

Filip111
Člen | 244
+
0
-

Dobrá zpráva pro tebe je, že na sandboxu to funguje dobře.

Zkusím tam postupně nabalovat zbytek kódu a snad se to v nějakým okamžiku zvrtne. Taky musim vyzkoušet nejnovější verzi, používám Nette 2.0.0

Filip111
Člen | 244
+
0
-

Bylo to o nervy a postupně jsem rozebíral celý projekt až na kost, ale dohledal jsem kde je problém – nette.ajax.js

HosipLan má v odkazovaném sandboxu – nějakou jinou verzi scriptu, já mám aktuální revizi g835c5e4
Je tam změna od řádku 305:

		settings.data = this.serializeValues(analyze.form, settings.data);
	}
}, {
	serializeValues: function ($form, data) {
		var values = $form.serializeArray();
		for (var i = 0; i < values.length; i++) {
			var name = values[i].name;
			if (name in data) {
				var val = data[name];
				if (!(val instanceof Array)) {
					val = [val];
				}
				val.push(values[i].value);
				data[name] = val;
			} else {
				data[name] = values[i].value;
			}
		}
		return data;
	}

Nevím přesně co to znamená, ani nevim jak přesně tenhle script funguje (poprvé jsem ho zkusil před dvěma týdny), ale vidím tam něco s formulářem, takže hádám že jsem trefil správně.

Můžete na to někdo kompetentní kouknout, případně navrhnout co s tím?

Díky.

Filip Procházka
Moderator | 4668
+
0
-

Jop, to byla ta oprava :) Problém byl celou dobu v ajax scriptu. Javascript totiž náhodně přehazuje prvky v objektu. Asi jsem ti to mohl říct rovnou, že ;D promiň :)

Tady je pull request pro Vojtu.

Editoval HosipLan (4. 9. 2012 15:01)

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

And… merged ;).

Filip111
Člen | 244
+
0
-

Bezva dík, aspoň že je to vyřešený (zkusim ještě poslední revizi).

Kdyby to bylo bez těch dvou hodin hledání, byla by nuda :c)
(dlouho jsem to hledal v Presenteru a až když jsem zjistil, že PHP kód vykopírovanej ze sandboxu u mě taky nefunguje, dohrabal jsem se postupně až k js).

Filip111
Člen | 244
+
0
-

Můžu potvrdit, že v aktuální verzi se to chová korektně.