Předání parametru do šablony komponenty – v ajaxovém requestu nefunguje
- m.brecher
- Generous Backer | 872
Ahoj!
když jsem ajaxoval standardní formulář Nette zabalený do UI\Control, narazil jsem na drobný problém.
předání parametru do šablony formuláře v šabloně presenteru:
{control 'myForm', heading: 'Editační formulář'} {* zde přenos parametrů v ajaxu NEfunguje *}
šablona formuláře:
<div n:snippet="control" class="base-form">
{form 'form'}
{include 'flashBox.latte', formId: $form->getElementPrototype()->id} {* zde přenos parametrů vždy funguje *}
<h2 n:ifcontent class="form-heading">{$heading}</h2> {* $heading je při ajaxu null *}
{dump $heading} {* dump ale $heading vypíše správně vždy *}
{/form}
</div>
komponenta formuláře:
class MyForm extends UI\Control
{
protected function createComponentForm(): BaseForm
{
$form = new BaseForm();
// .....
return $form;
}
public function render(?string $heading = null): void
{
$heading = 'Editační formulář'; // fix ajax latte chyby
$this->template->heading = $heading;
// ...
$this->template->render(__DIR__.'myForm.latte');
}
}
Do šablony formuláře předávám v šabloně presenteru parametr $heading. Při standardním requestu se tento parametr předá bez chyb. Když použiji ajaxový request pro submit formuláře (knihovna Naja), parametr $heading se NEPŘEDÁ. Přitom {dump} v šabloně komponenty vypíše hodnotu $heading SPRÁVNĚ.
Jde to snadno fixnout v metodě render() komponenty, ale bylo by dobré chybu vytrasovat a odstranit. Pokud budeme komponentu formuláře používat opakovaně, potom je optimální nastavovat $heading formuláře právě v konkrétní šabloně.
Díky
Editoval m.brecher (31. 10. 2023 18:31)
- mskocik
- Člen | 62
Renderovanie snippetov kompletne obchadza sablonu. A
SnippetDriver
vola render()
na komponente natvrdo.
private function renderChildren(): void
{
$queue = [$this->control];
do {
foreach (array_shift($queue)->getComponents() as $child) {
if ($child instanceof Renderable) {
if ($child->isControlInvalid()) {
$child->snippetMode = true;
$child->render();
$child->snippetMode = false;
}
} elseif ($child instanceof Nette\ComponentModel\IContainer) {
$queue[] = $child;
}
}
} while ($queue);
}
Ci uz je to optimalne, alebo by bolo vhodne umoznit nejaku customizaciu, je uz druha vec.
Editoval mskocik (31. 10. 2023 20:02)
- Kamil Valenta
- Člen | 820
Ona to není moc novinka, děje se to už tak cca 13 let. A určitě
ještě někde koluje video, kde to David Matějka popisuje.
Nepředávej ten parametr ze šablony, ale v parentu komponenty zavolej
patřičný setter.
- m.brecher
- Generous Backer | 872
@mskocik
Renderovanie snippetov kompletne obchadza sablonu.
Aha, pak už to chápu. Takže se vykreslí šablona komponenty ale hlavní šablona do které je šablona komponenty vložena se nevykreslí. To zní logicky a pak je jasné, že se do šablony komponenty ani nemůže předat žádný parametr z hlavní šablony. Toto by se také mohlo doplnit do dokumentace (pokud to tam někde už není), protože si tohle člověk těžko domyslí.
- m.brecher
- Generous Backer | 872
@KamilValenta
A určitě ještě někde koluje video, kde to David Matějka popisuje.
Video jsem pečlivě shlédnul, ale cca před rokem a problém lokálních parametrů tam @DavidMatějka skutečně důrazně zmiňoval. Pochopil jsem to ale nějak takto:
{var $param = 'value'}
{snippet 'mySnippet'}
{$param} {* no value *}
{/snippet}
Vůbec jsem si to nespojil s předáním parametrů do šablony v tagu {control}. Mrknu do dokumentace, jestli je tam tento aspekt zmíněn a popř. doplním.
- m.brecher
- Generous Backer | 872
@DavidGrudl
Nepomůže tady snippetArea okolo {control}?
Zkouším:
{* přidat snippetArea nepomáhá, $heading se nepředá *}
{snippetArea 'myFormWrapper'}
{control 'myForm', heading: 'Editační formulář'}
{/snippetArea}
To je škoda, protože předávat řídící/vykreslovací parametry do nějaké obecně použitelné latte šablony je výborný způsob jak zpřehlednit a strukturovat kód. Typické použití je:
a) doplnění nějakého nadpisu/popisky formuláře specifického v daném
presenteru
b) konfigurace funkce komponenty specificky podle umístění – třeba
navigační menu ve výchozím stavu zabaleno/rozbaleno
Dá se to snadno vyřešit předáním parametru do šablony v metodě render() abstraktního předka přes tryCall(‚afterRender‘) metody final potomka. Ale není to ideální místo, pro umístění statického textu do šablony.
V budoucnu by se mohla podpora Ajaxu v komponentách modernizovat a deklarovat Ajax komponenty UI\Control atributem:
#[Ajax]
final MyFormControl extends UI\Control
{
//.....
}
Atribut #[Ajax] by mohl řídit vše, co se dnes dělá ručně:
a) funkci komponenty – implementace v nějakém abstraktním předku,
final potomci by mohli být ajaxoví nebo ne
b) automatické přidání značky pro ajax do signálů komponenty v odkazech,
nebo do značky <form> ve formulářích
c) automatické obalení šablony komponenty do snippetu
d) ošetření předání parametru při vykreslování komponenty
Ad d) by se řešilo lépe, když by latte při vykreslování šablony komponenty vědělo, zda používá ajax nebo ne. V případě, že by:
– {control} komponenty obsahoval nějaké parametry,
– komponenta byla označena atributem #[Ajax]
mohlo by latte zapsat do přeložené šablony informaci, že se má spouštět nadřazená šablona a předat parametry.
Tudy by se mohly ubírat úvahy jak modernizovat ajax v komponentách Nette.
Editoval m.brecher (1. 11. 2023 15:52)
- mskocik
- Člen | 62
@mbrecher A nestačí ti používať custom render metódy, https://doc.nette.org/…n/components#…
a tam príklad s renderPaginator
? Teraz už vieš, že snippety
volajú render()
a v prípade klasického renderu môžeš
definovať props tak.
{control poll}
{control poll:paginator 123, 'hello'}
- David Grudl
- Nette Core | 8228
Zkusil jsem do nette/application 3.1-dev přidat podporu pro
{control}
uvnitř {snippetArea}
, aby tak šlo předat
parametry nebo volat jinou render metodu.
Ale snippety jsou dost komplexní věc, tak si nejsem jist, jestli jsem tím nic nerozbil.