LogicException Form declaration is missing
- m.brecher
- Generous Backer | 864
Ahoj,
při použití snippetů v šabloně formuláře jsem narazil na takovouto chybu.
Formulář je poděděný z UI\Control, do šablony do proměnné $form natvrdo předávám Form
public function render(): void
{
$template->form = $this->form; // Form
// ...
}
V šabloně formuláře mám blok {define ‚container‘}, který vkládám pomocí {include} a šablona se v pořádku vykresluje do chvíle, kdy značku {include ‚container‘} obalím snippetem:
{snippet 'control'}
<form n:name="$name">
.......
{snippet 'container'} {* this snippet makes exception *}
{include 'container'}
{/snippet}
</form>
{/snippet}
{define 'container'}
{do bdump($form)} {* variable $form exists *}
<div class="container">
......
{input 'name'} {* when commented out is OK *}
</div>
{/define}
Po obalení {include} snippetem vyhodí Latte výjimku:
LogicException
Form declaration is missing, did you use {form} or <form n:name> tag?
Snippet vykresluji pomocí $formControl->renderControl(‚container‘)
Proměnná $form uvnitř bloku existuje, výjimku vyhazuje značka {input ‚name‘}, kterou pokud zakomentuji tak se šablona vykreslí OK. Pokud odkomentuji {input ‚name‘} a zakomentuji {snippet ‚container‘} vykreslí se také OK.
Takže to vypadá, že bude asi nějaká chyba ve značce {input} pokud je v bloku, který se vkládá {include} a ten je uvnitř snippetu.
latte/latte v3.0.18
Editoval m.brecher (12. 10. 13:25)
- Marek Bartoš
- Nette Blogger | 1263
Proměnnou $form ti definuje makro {form formName}
, případně
<form n:name='formName'>
. Při překreslení snippetu se
makro nevykoná, protože je mimo snippet, a tak uvnitř snippetu proměnná
není dostupná. Řešení je definovat ve snippetu kontext formuláře,
přes {formContext $control['formName']}
Určitě by bylo fajn tohle chování vylepšit. Napadá mě k tomu pár možností:
- ve výjimce uvést informaci o formContext, pokud jsme uvnitř snippetu neobsahujícího form
- ve snippetu nemít proměnnou automaticky deklarovanou, i když se jedná o ne-ajaxový request (možná to tak už je, netuším)
- při kompilaci se podívat, zda snippet není uvnitř formuláře a vytvořit formContext interně podle formuláře (to však nebude fungovat vždy, skládání šablon může být dynamické)
Proměnná $form uvnitř bloku existuje
I při ajaxovém requestu?
- m.brecher
- Generous Backer | 864
@MarekBartoš
Proměnnou $form ti definuje makro {form formName}, případně <form n:name=‚formName‘>. Při překreslení snippetu se makro nevykoná, protože je mimo snippet, a tak uvnitř snippetu proměnná není dostupná.
Proměnnou $form jsem si do šablony předal natvrdo je k dipozici všude v šabloně (i ajax). Tag {input ‚name‘} ale neumí $form ze šablony použít, bezpochyby proto, že používá jinou „interní“ proměnnou.
Řešení je definovat ve snippetu kontext formuláře, přes {formContext $control[‚formName‘]}
Díky, skvělý nápad, toto funguje:
{snippet 'container'}
{formContext $form} {* $form injected to template by hand *}
{include 'container'}
{/formContext}
{/snippet}
Z dokumentace Latte byl ale tag {formContext} odstraněn a plugin Latte Pro tento tag označuje jako deprecated takže @DavidGrudl bezpochyby plánuje jeho definitivní zrušení a nahradí ho asi s nějakým lepším řešením.
Výstupem diskuze v tomto vlákně je zjištění, že označením tagu {formContext} jako deprecated vznikl problém ajax snippetů uvnitř formulářů. Pro funkci snippetu uvnitř formuláře je použití tagu {formContext} bezpochyby nutné.
Pokud by se nedařilo nějaké „lepší“ řešení pro snippety ve formulářích najít, mohlo by se řešení s tagem {formContext} ponechat a odebrat mu tag deprecated + dát popis do dokumentace.
Dočasným řešením je překreslovat vždy celý formulář.
Editoval m.brecher (13. 10. 12:37)
- m.brecher
- Generous Backer | 864
@MajklNajt
ja to obchádzam napríklad takto: …
Na vykreslení dat z objektu formuláře např. $flashes to stačí. Na vykreslení formulářových prvků pomocí makra {input} nikoliv, a právě tento případ zde řešíme.
I když si do šablony proměnnou $form předáš ručně tak ti makra {input} ve snippetu i tak vyhodí výjimku – makro {input} neumí použít ručně předanou proměnnou $form. Jediné řešení, na které přišel @MarekBartoš je použít tag {formContext}, který je ale deprecated a bezpochyby bude z Latte v budoucnu vyřazen.
- MajklNajt
- Člen | 494
m.brecher napsal(a):
Na vykreslení dat z objektu formuláře např. $flashes to stačí. Na vykreslení formulářových prvků pomocí makra {input} nikoliv, a právě tento případ zde řešíme.
to je kravina, prekresluje mi to aj formulárové prvky vytvárané cez
{input}
, {label}
… mám to celé obalené do
snippetArea
, ktorú samozrejme tiež invalidujem
EDIT: a teda používam aj {formContainer}
, možno preto mi to
funguje
{snippetArea myFormContainer}
{form myForm, class => "ajax"}
...
{snippet personal}
{formContainer personal}
{foreach $formContainer->getComponents() as $i}
<p {if $i->hasErrors()}class="input_error"{/if}>{label $i /}{input $i}</p>
{/foreach}
{/formContainer}
{/snippet}
...
{snippet contact}
{formContainer contact}
{foreach $formContainer->getComponents() as $i}
<p {if $i->hasErrors()}class="input_error"{/if}>{label $i /}{input $i}</p>
{/foreach}
{/formContainer}
{/snippet}
...
{snippet billing}
{formContainer billing}
{foreach $formContainer->getComponents() as $i}
<p {if $i->hasErrors()}class="input_error"{/if}>{label $i /}{input $i}</p>
{/foreach}
{/formContainer}
{/snippet}
...
{/form}
{/snippetArea}
Editoval MajklNajt (15. 10. 12:12)
- m.brecher
- Generous Backer | 864
@MajklNajt
to je kravina, prekresluje mi to aj formulárové prvky vytvárané cez {input}, {label}… mám to celé obalené do snippetArea, ktorú samozrejme tiež invalidujem
Tag {snippetArea} to neřeší, ten řeší snippety v includované podšabloně – což není ten případ, ale:
a teda používam aj {formContainer}, možno preto mi to funguje
toto je správné řesení! Díky moc za důležitou informaci, protože po zabalení problematických tagů {input} do {formContainer} je problém vyřešen:
{snippet 'container'}
{formContainer 'container'} {* po přidání {formContainer} je to OK !!! *}
{input 'name'}
{/formContainer}
{/snippet}
Takže deprecated tag {formContext} není nutné používat. V dokumentaci Latte je ale popis funkce {formContainer} nedostatečný:
citace: “S vykreslením prvků uvnitř formulářového kontejneru
pomůže tag {formContainer}”
viz: https://doc.nette.org/…ms/rendering#…,
V dokumentaci nette – ajax snippety tato důležitá informace chybí úplně.
Bylo by určitě vhodné nutnost použití tagu {formContainer} ve vnořených snippetech ve formulářích do dokumentace Nette – Snippety doplnit. Jak ukázalo toto vlákno, ani zkušení vývojáři jako @MarekBartoš nebo @MajklNajt nedokázali napoprvé poradit správné řešení.
Editoval m.brecher (15. 10. 17:00)
- Marek Znojil
- Člen | 90
Ahoj, pamatuji si, že jsem řešil něco podobného a napadlo mě, že bys mohl zkusit nahradit:
{snippet 'container'}
{formContainer 'container'} {* po přidání {formContainer} je to OK !!! *}
{input 'name'}
{/formContainer}
{/snippet}
Za:
{snippet 'container'}
{input $form['name']}
{/snippet}
Předáš tagu rovnou instanci komponenty. A pokud ti to projde, tak si myslím, že je problém přímo v tagu {input}.
Raději jsem ještě narychlo zkusil simulaci a dle všeho to tak vypadá:
{form form, class: 'ajax'}
{snippet form}
{var $form = $control['form']}
{input $form['name']} // projde
{input $form['send']}
{/snippet}
{/form}
{form form, class: 'ajax'}
{snippet form}
{var $form = $control['form']}
{input name} // Form declaration is missing, did you use {form} or <form n:name> tag?
{input $form['send']}
{/snippet}
{/form}