Prázdná hodnota MultiSelect při ajaxovém načtení položek

Odo
Člen | 48
+
0
-

Ahoj všem,

narazil jsem na problém s MultiSelectem při použití Select2, ale zřejmě to bude obecně platit pro jakékoliv načítání <option> ajaxem.

Následující kód funguje bez problémů (všechny položky zadám v konstruktoru):

	$form->addMultiPicker('folder_ids', 'Přiřazení do složek', $this->model->getFolders())
		->setRequired(false);

Následující kód způsobí, že při zpracování formuláře bude $values->folder_ids = [] – položky načítám přes ajax až při vykreslení šablony):

	$form->addMultiPicker('folder_ids', 'Přiřazení do složek', [])
		->setRequired(false);

Pokud konstruktoru předám pole uživatelem zvolených položek, $values->folder_ids mi vrací jen tyto hodnoty, nikdy ne ty načtené ajaxem. Začínám tušit, že to asi bude mít nějakou souvislost s validací nebo zpracováním formuláře – Nette si zřejmě myslí, že položky načtené ajaxem nepatří mezi povolené hodnoty zadané v konstruktoru MultiSelectu a tak je odmaže. Jakým způsobem to mohu opravit?

Předem díky za rady!

Editoval Odo (20. 4. 2020 21:56)

Odo
Člen | 48
+
0
-

Problém jsem vystopoval až k nikde nepopsané proměnné / metodě checkAllowedValues / checkDefaultValue. Nicméně i přes jakoukoliv snahu tam nacpat false zpracování formuláře zemře při validaci (javascriptem dodaná položka je mimo rozsah), takže do metody onSuccess se ani nedostanu :(

Splácal jsem hack, který před addSelect() přečte getHttpData a pokud hodnota není v datech, tak ji tam přidá. Hodně ošklivé, ale celkem jednoduché řešení.

class BaseForm extends Nette\Application\UI\Form
{

    // ...

	function addTextSelect($label, $name, $data = [])
	{
		// pokud položka neexistuje, přidáme ji
		$values = $this->getHttpData();
		if (isset($values[$label])) {
			$text = $values[$label];
			if (!isset($data[$text]) && $text !== '') $data[$text] = $text;
		}
		// přidáme normální select
		return parent::addSelect($label, $name, $data);
	}
}

Nebo mě napadlo přidat skryté textové pole, přes které se bude hodnota selectu přenášet, což je z hlediska Nette asi čistější řešení, ale zase javascript navíc…

Mimochodem je tu docela dost vláken na toto téma, žádné s řešením.

Editoval Odo (29. 4. 2020 16:04)

Šaman
Člen | 2641
+
0
-

Nejspíš narážíš na stejný problém, jaký se řeší v závislých selectboxech. Ano, je nutné nastavit příjimacímu formuláři (tomu co bude na stránce po odeslání) platné hodnoty, jinak všechny pro něj neznámé hodnoty zahodí (kvůli bezpečnosti, mohou být podvržené).

Takže můžeš zkusit googlit zavislé formuláře v Nette – sám ale nevím, jestli všechna řešení zůstala stejná i pro nové Nette. Budu to muset odzkoušet. U těch závislých selectboxů je nutné nastavit do závislého selectu hodnoty podle toho, co je vybrané v nezavislém selectu, většinou přímo v továrně na formulář.

Pokud ty hodnoty ajaxem bereš úplně jinde a není možné je nastavit při vytváření formuláře, pak je asi nejlepší tahat je z getHttpData(). Nebo použít ten tvůj hack, ale pokud může být podvržená nebezpečna hodnota, tak by bylo dobré před přidáním té hodnoty do formuláře nějak ji ošetřit.

Editoval Šaman (29. 4. 2020 16:41)

Odo
Člen | 48
+
+1
-

Teď jsem si uvědomil, že vlastně potřebuji „autocomplete“, tj. uživatel zadá co chce, přičemž si může ušetřit čas výběrem z předdefinovaných položek. Tudíž „podvržení“ hodnoty uživatelem je žádané a bezpečné. Můžu to tudíž předělat na normální Text input, se kterým si pohraju v JS. Výhoda Select/MultiSelect pro mě byla v tom, že jsem si teoreticky mohl vybrat, jestli jim do konstruktoru nacpu položky, nebo je načtu až skriptem. Když to vyřeším přes Text, tak ty položky musím načíst přes AJAX vždy :)

Editoval Odo (29. 4. 2020 17:11)