Překreslení vybraných dynamických snippetů uvnitř snippetArea

- nefilskyl
- Člen | 2
Mám otázku, která míří na tělo, přímo k designu snippetů, a na kterou nemůžu najít odpověď: Proč Nette neumožňuje více dynamických snippetů, které by šlo nezávisle invalidovat, uvnitř jednoho rodičovského? Kostlivec ve skříni, nebo záměr?
Use case:
Na jednom starším projektu (ale to je irelevantní) se používá knihovna
kdyby/forms-replicator pro dynamické přidávání/odebírání částí
formuláře. V jednom formuláři chci uvnitř dynamického kontejneru použít
závislé selectboxy. Ano, můžu si data vrátit jako JSON a selecty naplnit
v JS, ale proč to dělat, když v Nette máme snippety..? :-) Nabízí se
jednoduchá implementace překreslování dynamických kontejnerů pomocí
dynamických snippetů:
{form form class => 'ajax'}
{snippetArea orderItems}
{var $form = $control['form']}
<fieldset n:foreach="$form['items']->getContainers() as $idx => $item">
{input $item['subscriber']}
{snippet subscriberBranch-$idx}
{input $item['subscriberBranch']}
{/snippet}
{input $item['product']}
{snippet productStack-$idx}
{input $item['productStack']}
{/snippet}
{input $item['remove'], 'class' => 'btn btn-danger pull-right'}
</fieldset>
{/snippetArea}
{input items-add, 'class' => 'btn btn-success'}
<div class="form-actions">
{input save class => 'btn btn-primary pull-right'}
</div>
{/form}
$item představuje jeden kontejner dynamicky vytvořený pomocí
form replicatoru. Po výběru prvku v selectu subscriber se zpracuje
příslušný signál komponenty – načtu data pro subscriberBranch a
invaliduji orderItems a subscriberBranch (a chtěl bych překreslit pouze tento
snippet), stejně tak po výběru produktu by se měl překreslit pouze
productStack. To ale implementace neumožňuje, vždy dojde k překreslení
všech dynamických snippetů uvnitř snippetArea – viz podmínka
v Latte\Runtime\SnippetDriver::enter():
public function enter($name, $type)
{
if (!$this->renderingSnippets) {
return;
}
$obStarted = FALSE;
if (($this->nestingLevel === 0 && $this->bridge->needsRedraw($name))
|| ($type === self::TYPE_DYNAMIC && ($previous = end($this->stack)) && $previous[1] === TRUE)
) {
ob_start(function () {});
$this->nestingLevel = $type === self::TYPE_AREA ? 0 : 1;
$obStarted = TRUE;
} elseif ($this->nestingLevel > 0) {
$this->nestingLevel++;
}
$this->stack[] = [$name, $obStarted];
$this->bridge->markRedrawn($name);
}
Je to kód ze starší verze (protože momentálně řeším starý projekt),
ale zdá se, že aktuální zdrojáky obsahují totožnou logiku (https://github.com/…tRuntime.php).
Nešlo by to udělat tak, aby se i v případě dynamických snippetů
kontroloval název? Přesná shoda (např. „subscriberBranch-0“) by myslím
prošla i první částí podmínky a v druhé
(($type === self::TYPE_DYNAMIC && ...) by bylo možno
např. kontrolovat zda odpovídá prefix, případně zavést nějaký
placeholder pro invalidaci všeho. Nebo ne?

- m.brecher
- Generous Backer | 917
@nefilskyl
Dynamické snippety nepoužívám, standardně vždy dávám snippet na celou tabulku do tagu <table>. Dynamické snippety jsem si otestoval a zjistil, že fungují jinak, než jsem si myslel. Dynamické snippety typicky nastaví ve foreach na každý řádek unikátní id <tr id=„snippett–aticle->1“> a člověk bez přemýšlení předpokládá, že bude možné jednotlivé řádky samostatně překreslit.
Tak ale dynamické snippety nefungují – pokud se invaliduje obalující statický snippet nebo snippet area, nette vždy odešle do payload VŠECHNY jednotlivé dynamické snippety samostatně (testováno). To znamená, že se překresluje se celá tabulka, ale ušetříš tagy <table> a <thead> a jede řádek v záhlaví. Je úplně jedno, jestli nastavíš po invalidaci statického obalujícího snippetu invalidaci jednoho konkrétního snippetu, tato invalidace se ignoruje. Bylo to tak asi vždycky, není to žádná změna v latte.
Dynamické snippety by dávaly smysl, kdyby a) síť a servery byly pomalý jako dřív, b) kdyby bylo možno cíleně překreslit jednotlivé snippety. Dnes jsou servery tak výkonné, že použít dynamické snippety je neekonomické – složitější kód, složitější html a navenek to nikdo nepozná. A to i kdyby byly dotažené do možnosti překreslit jeden řádek – to je asi důvod, proč se tato feature nedotáhla do konce.
Tvůj popisovaný use-case s interakcí závislých selectboxů v containeru už dle mého názoru není vhodná úloha pro snippety, ale pro pár řádků javascriptu. Snippety jsou na chytrou interakci příliš těžkopádné.
Místo komplikovaného dotažení dynamických snippetů do původní myšlenky bych navrhoval je z dokumentace úplně vyřadit s poznámkou, že dnes už výkonnostně nedávají smysl.