Vnořené dynamické snippety

zizka
Člen | 9
+
0
-

Zdravím, už nějaký čas s nette trochu pracuji, ale v dynamických snippetech pořád trochu tápu. Momentálně bojuji s tím, jak zprovoznit vnořené dynamické snippety tak, aby se mi přes ajax posílaly jenom ty, které potřebuji.

Potřeboval bych vyrobit tabulku, ve které jsou nějaké souhrnné informace. Po kliknutí na řádek by se mi měly zobrazit nějaké doplňkové informace spolu s dalším seznamem, který se chová stejně, tzn. po kliknutí na řádek seznamu se mi zobrazí nějaký detail. Docílit bych chtěl toho, aby se mi při úvodním reloadu stránky nahrála celá tabulka, pak při kliknutí na řádek by se nahrál jenom nový obsah toho řádku a při kliknutí na prvek vnořeného seznamu by se nahrály jenom informace o detailu.

Zjednodušená struktura je následující:

<?php
<div n:snippet="seznam">
  {foreach ... $idZaznamu}
    <div n:snippet="zaznam-$idZaznamu">
      <div class="hlavickaZaznamu">
        <a n:href="ZobrazZaznam! $idZaznamu">Zobrazit</a>
      </div>
      {if zobrazitTentoZaznam}
        <div class="obecneInfo">
          zde jsou obecné informace, které ale nechci nahrávat při každém subrequestu znovu
        </div>
        <div n:snippet="seznamInformaci-$idZaznamu">
          {foreach ... $idInformace}
            <div n:snippet="hlavickaInformace-$idInformace">
              <a n:href="ZobrazInformaci! $idInformace">Zobrazit</a>
              {if zobrazitTutoInformaci}
                <div class="konkretniInformace">zde jsou informace, ktere se zobrazi na pozadani</div>
              {/if}
            </div>
          {/foreach}
        </div>
      {/if}
    </div>
  {/foreach}
</div>
?>

Chtěl bych, aby se po po handleru handleZobrazZaznam se aktualizoval snippet „zaznam-$idZaznamu“ a po handleru handleZobrazInformaci aktualizoval jenom příslušný snippet „seznamInformaci-$idZaznamu“. Zatím jsem to byl schopen donutit dělat jenom to, aby se pokaždé nahrál znovu snippet záznam, jenomže jelikož v těch obecných informacích jsou i nějaké obrázky atd., tak to celé pořád nepříjemně problikává a navíc je zbytečné to pořád nahrávat znovu. Lze toho nějak docílit? Různým obalováním snippety atd. se mi nepodařilo nic vymyslet, maximálně jsem dosáhnul toho, že se mi posílaly snippety, které nejsou zobrazené, takže se neaktualizovaly. Je někde nějaký návod, jak se to vlastně má dělat správně?

David Matějka
Moderator | 6445
+
+1
-

ahoj, zanorene dyn snippety se resi tezko/spatne. bude lepsi, kdyz to obalis do komponent

zizka
Člen | 9
+
0
-

Ahoj, díky, zkusím to tak.

zizka
Člen | 9
+
0
-

Tak jsem to vyrobil, ale chová se to v zásadě úplně stejně. Nevidím do toho, jak to přesně interně funguje, ale z toho, co jsem načetl to vypadá, že Nette vlastně neví, že má vykreslit jenom jeden snippet/komponentu, toho docílím tím, že do vykreslování pošlu místo pole prvků jenom jeden prvek. Problém s vnořenými snippety/komponentami je ale v tom, že bych potřeboval do vykreslování poslat jenom část prvku. Když chci překreslit jednu „Informaci“, tak musím do vykreslování poslat příslušný „Záznam“ s touto jednou „Informací“. Tím ale dojde vedle překreslení „Informace“ i k překreslení toho celého „Záznamu“ (v mém příkladu nahoře to je div .obecneInfo), což nechci. Jak se to má dělat?

David Matějka
Moderator | 6445
+
0
-

ukaz, jak to mas ted

Kcko
Člen | 465
+
0
-

David Matějka napsal(a):

ahoj, zanorene dyn snippety se resi tezko/spatne. bude lepsi, kdyz to obalis do komponent

Není až tak pravda ne? Viz ukázkový příklad, kde je ukázano co udělat, aby se poslal skutečně jen 1 snippet a ne všechno

https://doc.nette.org/…ication/ajax#…

David Matějka
Moderator | 6445
+
0
-

@Kcko problem je, ze tam jsou dynamicke snippety zanorene

<div n:snippet="zaznam-$idZaznamu">
....
        <div n:snippet="seznamInformaci-$idZaznamu">
			....
			<div n:snippet="hlavickaInformace-$idInformace">
Kcko
Člen | 465
+
0
-

jasně moje chyba, blbě sem to precetl.

zizka
Člen | 9
+
0
-

Pokusil jsem se vysápat z aplikace co nejjednodušší verzi:

Presenter:

<?php
class SamplePresenter extends BasePresenter
{
	public function renderDefault()
	{
		$this->template->zaznamy=$this->model->getData();
	}

	protected function createComponentZaznam()
	{
		return new UI\Multiplier(function($cislo)
		{
			$control=$this->zaznamControlFactory->create();
			$control->setCislo($cislo);
			$control->redrawControl();
			return $control;
		});
	}
}
?>

Šablona presenteru:

{block content}

<table>
{foreach $zaznamy as $zaznam}
	{var $zaznamId=$zaznam['id']}
	{control zaznam-$zaznamId}
{/foreach}
</table>

{/block}

ZaznamControl.php:

<?php
class ZaznamControl extends UI\Control
{
	public function setZaznamId($zaznamId)
	{
		$this->zaznamId=$zaznamId;
	}

	public function render()
	{
		$zaznamy=$this->model->getData();

		$template=$this->template;
		$template->show=$this->show;
		$template->zaznamId=$this->zaznamId;
		$template->zaznam=$zaznamy[$this->zaznamId];
		$template->zaznamy=$zaznamy;
		$template->render(__DIR__ . '/ZaznamControl.latte');
	}

	public function handleShow()
	{
		$this->model->getData($this->zaznamId);

		$this->show=!$this->show;
	}

	protected function createComponentInfo()
	{
		return new UI\Multiplier(function($infoId)
		{
			$control=$this->infoControlFactory->create();
			$control->setZaznamId($this->zaznamId);
			$control->setInfoId($infoId);
			$control->redrawControl();
			return $control;
		});
	}
}
?>

ZaznamControl.latte:

<tbody n:snippet="zaznam">
	<tr>
		<td><a href="{link show}" class="ajax">{$zaznamId}</a></td>
	</tr>
	{if $show}
	<tr>
		<td colspan="20">
			<table>
				<tr>
					<td>
						... obecné informace
					</td>
					<td>
						<table>
							{foreach $zaznam['info'] as $info}
								{var $infoId=$info['id']}
								{control info-$infoId}
							{/foreach}
						</table>
					</td>
				</tr>
			</table>
		</td>
	</tr>
	{/if}
</tbody>

InfoControl.php:

<?php
class InfoControl extends UI\Control
{
	public function render()
	{
		$zaznamy=$this->model->getData();

		$template=$this->template;
		$template->show=$this->show;
		$template->zaznamId=$this->zaznamId;
		$template->infoId=$this->infoId;
		$template->zaznam=$zaznamy[$this->zaznamId];
		$template->info=$zaznamy[$this->zaznamId]['info'][$this->infoId];
		$template->render(__DIR__ . '/InfoControl.latte');
	}

	public function handleShow()
	{
		$this->model->getData($this->zaznamId);

		$this->show=!$this->show;
	}
}
?>

InfoControl.latte:

<tbody n:snippet="info">
	<tr>
		<td><a href="{link show}" class="ajax">{$info['nazev']}</a></td>
	</tr>
	{if $show}
		... podrobnosti
	{/if}
</tbody>

Pochopitelně spousta pro tento problém nepodstatných drobností okolo je vynechaná.

Co bych tedy potřeboval je to, aby v případě, že kliknu na {link show} od komponenty InfoControl, došlo k tomu, že se na klienta odešle jenom znovu vygenerovaný příslušný snippet InfoControl. Teď to proběhne tak, že se pošle celý obsah nadřízeného ZaznamControl.

David Matějka
Moderator | 6445
+
0
-

problem imho bude jen to, ze volas $control->redrawControl(); uz v multiplieru, takze invalidujes cely ten zaznam. zkus to volat pouze v handleShow. jinak ten kod vypada spravne

zizka
Člen | 9
+
0
-

Tak to bylo ono. Děkuji.