Ztráta vybraných „radio“ možností při serverové validaci formuláře – inputy skrz vlastní Latte filtr

MikKuba
Člen | 76
+
0
-

Ahoj,

Mám formulář, ve kterém kromě klasických radio inputů, checkboxů a textových polí je také input, který se ale vytváří skrz Latte filtr – je uvnitř formuláře, odesílá se.

Jenže při validaci, kdy se kontroluje vyplněnost a případně vrací s neúspěchem takto:

return $this->onErrorAccess('Není vyplněna odpověď na povinnou otázku: '. $question->question);

tak při zpětném načtení formuláře zůstanou s odeslanými hodnotami vyplněné text inputy, i klasické seznamy radio a checkboxy.
Jenže některé radio listy jsou zde pomocí Latte filtru, který případně z textu na základě hodnot v data-values vypisují dané hodnoty jako „tlačítka“ vedle sebe. No a tyto „radio“ možnosti se zpětně nevyplní.

Filtr pracuje takto:

private function replaceSelectAnswer(string $content): string
	{
		$this->counter = 0;
		return Strings::replace($content, '~<a(?<args>[^>]*data-widget="selectanswer"[^>]*)>.*?</a>~', function ($matches) {
			$parameters = [
				'values' => json_decode(htmlspecialchars_decode(Strings::match($matches['args'], '~data-values="([^"]*)"~')[1] ?? 0)),
			];

			$parameters['id'] = $this->id . "_" . ++$this->counter;

			return $this->renderTemplate('selectanswer.latte', $parameters);
		});
	}

A šablona je vykresluje takto:

<label class="selectanswer-block">
	<label>
		<input class="selectanswer-input" type="radio" name="answer{$id}" value="{$values->option1}"/>
		<span>{$values->option1}</span>
	</label>
	<label>
  		<input class="selectanswer-input" type="radio" name="answer{$id}" value="{$values->option2}"/>
  		<span>{$values->option2}</span>
  	</label>
</label>

Při zkoumání se u klasických radio listů těm předtím zvoleným možnostem nastaví „checked“ a ve formuláři zůstanou, ale těmto nikoliv.

Dokázal by mi prosím někdo poradit, čím to může být? Zkoušel jsem i přidat jQuery:

$( document ).ready(function() {
  $('.selectanswer-input').click(function(){
      $(this).attr('checked', 'checked');
  });
});

kterým jsem si ty checked rovnou přidával už při klikání, ale po té validaci a vrácení s chybou se to stejně nezvolilo zpětně a atribut „checked“ se smazal.

Předem moc díky!

dakur
Člen | 493
+
0
-

@MikKuba A jak vykresluješ tu šablonu s tím filtrem?

MikKuba
Člen | 76
+
0
-

dakur napsal(a):

@MikKuba A jak vykresluješ tu šablonu s tím filtrem?

Pokud se jedná o typ „selectanswer“, tak se volá ten filtr pro nahrazení, volá se takto:

{if $question->type === "selectanswer"}
  {$question->question|exerciseTypes:$question->id|noescape}
{/if}

Nicméně tento problém se objevuje i u některých další prvků formuláře, proto spíš chystám skript, který před odesláním prvně zkontroluje, zda jsou všechny povinné inputy (ale nikoliv označené jako required) vyplněné a teprve potom to dovolí odeslat. I z hlediska zatížení, běží to totiž na sdíleném hostingu a nemá to dostatečnou kapacitu PHP procesů v momentě, kdy je tam nával několik desítek lidí v jeden okamžik, tak někteří musí request opakovat. Tímto teda trochu ušetřím requesty, že formulář se odešle skutečně až po vyplnění a nebude ho to vracet jako neúplný.

Editoval MikKuba (30. 3. 2021 8:53)

dakur
Člen | 493
+
0
-

Nevím, jak máš dělané ty ostatní prvky, ale pokud je to normálně field v Nette Forms přes např. $form->addText(), tak pak se nemůžeš divit. Vlastně sis odpověděl sám:

Při zkoumání se u klasických radio listů těm předtím zvoleným možnostem nastaví „checked“ a ve formuláři zůstanou, ale těmto nikoliv.

Ve výchozím stavu Nette Forms zajišťují vykreslování HTML a dosazení správných hodnot/atributů do něj:

$form->addSelect('vyber', [1 => 'první položka', 2 => 'druhá položka']);
$form->setDefaultValues(['vyber' => 2]);
{control $select}
 ↓
<select name="vyber" id="frm-vyber">
  <option value="1">první položka</option>
  <option value="2" selected>druhá položka</option>
</select>

Pak existuje manual rendering v Nette Forms, kdy sice píšeš HTML, ale pomocí makra n:name propojíš toto HTML s Nette fieldy, takže Nette zajistí dosazení správných hodnot/atributů:

<select n:name="neco" id="jine-id" />{* můžu libovolně přepisovat či přidávat atributy *}
 ↓
<select name="vyber" id="jine-id">
  <option value="1">první položka</option>
  <option value="2" selected>druhá položka</option>
</select>

Ty ale renderuješ „radio listy“ úplně manuálně, tj. vůbec nevyužíváš pro tato pole Nette Forms, takže není nic, co by jim nastavilo ten atribut checked – musíš se o to postarat sám. Do šablony tedy doplníš podmínku, kdy se má atribut checked vyrenderovat:

<label class="selectanswer-block">
	<label>
		<input class="selectanswer-input" type="radio" name="answer{$id}" value="{$values->option1}"{if $neco === $values->option1} checked{/if}/>
		<span>{$values->option1}</span>
	</label>
	<label>
  		<input class="selectanswer-input" type="radio" name="answer{$id}" value="{$values->option2}"{if $neco === $values->option2} checked{/if}/>
  		<span>{$values->option2}</span>
  	</label>
</label>

Přičemž $neco jsou data z HTTP požadavku, to si budeš muset vytáhnout v presenteru.

Editoval dakur (30. 3. 2021 12:49)