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

nefilskyl
Člen | 2
+
0
-

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
+
0
-

@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.