Dynamicky závislý select – výchozí hodnoty

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

Zdravím,
snažím se přijít na to, jak nastavit výchozí hodnoty u selectu závislém na jiném selectu. Použil jsem vzor odsud.

Problém:
Když se formulář rendruje je logické, že chci, aby se ke zvolené zemi načetly i odpovídající časové pásma. Ale když se formulář odesílá provede se opět načtení výchozích hodnot a k nově zvolené zemi se načte výběr časových pásem k zemi staré a vyhodí se chyba Please select a valid option.

Příklad:
Současná země je Czech a časové pásmo je Europe/Prague. Vyberu si novou zemi Greenland a k ní se mi načtou odpovídající 4 časové pásma. Když formulář odešlu s country (Greenland) není problém ale v timezone mám zase výběr Europe/Prague a snažím se tam vecpat America/Thule.

Kód:

protected function createComponentGeneralForm()
{
	$form = new Form;
	$form->setTranslator($this->translator);

	// další nepodstatné prvky

	$form->addSelect('country', 'Country', $this->settings->getCountriesSelect())
		->setTranslator(NULL);

	$form->addSelect('timezone', 'Timezone', array_combine(
		DateTimeZone::listIdentifiers(DateTimeZone::ALL),
		DateTimeZone::listIdentifiers(DateTimeZone::ALL)))
	->setTranslator(NULL);

	$form->addSubmit('submit', 'Save');
	$form->addButton('reset', 'Reset')
		->setAttribute('type', 'reset');

	$frontendId = $this->frontend->id;
	$values = array();

	try {
		$frontendValues = $this->frontends->getSettings($frontendId, TRUE);

		foreach ($frontendValues as $key => $value) {
			$values[$key] = $value;
		}

		$form->setDefaults($values);

		if ($values['country'])
			$form['timezone']->setItems(array_combine(
				DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $values['country']),
				DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $values['country'])
			));

	} catch (\Nette\Application\ApplicationException $e) {
		$form->addError($this->translator->translate($e->getMessage()));
	}

	$form->onSuccess[] = function (Form $form) use ($frontendId, $values) {
		// do something
	};

	return $form;
}
public function handleLoadTimezonesSelect($value)
{
	if ($value) {
		$this['generalForm']['timezone']->setItems(array_combine(
			DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $value),
			DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $value)
		));
	}
	$this->redrawControl('timezones-select');
}

K téhle podmínce jsem se snažil dodat !$form->isSubmitted() ale vyhodilo „Form is not anchored …“

if ($values['country'] && !$form->isSubmitted())
	$form['timezone']->setItems(..)
sKopheK
Člen | 207
+
0
-

Před zpracováním odeslaných dat se formulář musí znovu vytvořit a metoda na zpracování dat dostane tedy defaultní formulář, který neměl co do činění s tím handlem. Podobně pak volání isSubmitted() před doděláním formuláře a jeho přiřazení k presenteru / komponentě.

VojtaSim
Člen | 55
+
0
-

sKopheK napsal(a):

Nějaký nápad jak to zprovoznit? Napadá mě sessions.
Ale spíše, protože to je taková vychytávka, aby to bylo super-user-friendly tam ten defaultní výběr nedávat.

sKopheK
Člen | 207
+
0
-

Pokud to chápu dobře, bez zvolené země tam máš pásma všechna. Když zvolíš zemi, nastav všechna pásma až na ty odpovídající skrytá a disabled, aby je uživatel nemohl vybrat.

VojtaSim
Člen | 55
+
0
-

sKopheK napsal(a):

Pokud to chápu dobře, bez zvolené země tam máš pásma všechna. Když zvolíš zemi, nastav všechna pásma až na ty odpovídající skrytá a disabled, aby je uživatel nemohl vybrat.

Já jsem to nakonec vyřešil tak, že v časových pásmech je jen prompt „Select country first“ a až po vybrání země se načtou příslušné časové pásma a odstraní se prompt. A při validaci jednoduchá podmínka jestli jestli jsou obě hodnoty nastavené.