Vnořené snippety – prý nejdou, takže jak to napodobit?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
medhi
Generous Backer | 255
+
0
-

Ahoj, moc mi chybí možnost vnořených snippetů. Mám totiž tento případ:

Galerie fotek – jednotlivé fotky se prohlížejí ve snippetu (předchozí, další). Ke každé fotce chci však dát widget Voter, což je control – hlasovátko, které samo o sobě je snippetované. To už máme ale dva snippety v sobě, a tak hlasovátko nefunguje. Podařilo se mi pouze rochodit u něj handle, takže zahlasuje, ovšem už se nepřekreslí.

Netuším, jak tento případ jinak elegantně vyřešit, pomůžete? Nebo snad brzy půjdou vnořovat snippety?

Nette: 0.9.4

Matúš Matula
Člen | 257
+
0
-

Vo verzii 0.9.0 alebo mozno aj 0.9.1 to funguje, neviem, ci aj oficialne, ale mne to slape a vlastne len kvoli tomu som nepresiel na novsiu verziu..
to vnorovanie by sa fakt hodilo..

Mikulas Dite
Člen | 756
+
0
-

Jako workaround se dá použít jeden snippet navíc, tzn rozdělit to na část před hlasovadlem, to a část po něm. Je to ale divný invalidovat. (Plus je to nesmysl, když je jich víc než dva, resp. tři).

Ale vnořené snippety by byly dobré, to jo.

Ola
Člen | 385
+
0
-

Pokud to hlasovátko bude komponenta, pak by mohlo/mělo (ale not sure) jít vložit snippet do šablony tý komponenty. Tedy pak by šablona view mohla vypadat třeba takhle:

@{block #content}
{snippet something}
Jedna
{widget someVoterControl}
Dva
{/snippet}

A widgetu:

{snippet}
<a href="{link vote}">Hlasuj</a>
{/snippet}

Mám pocit, že v trošku starší verzi jsem přesně tohle používal.

Editoval Ola (10. 5. 2010 20:11)

Matúš Matula
Člen | 257
+
0
-

Ola napsal(a):

Pokud to hlasovátko bude komponenta, pak by mohlo/mělo (ale not sure) jít vložit snippet do šablony tý komponenty. Tedy pak by šablona view mohla vypadat třeba takhle:

@{block #content}
{snippet something}
Jedna
{widget someVoterControl}
Dva
{/snippet}

A widgetu:

{snippet}
<a href="{link vote}">Hlasuj</a>
{/snippet}

Mám pocit, že v trošku starší verzi jsem přesně tohle používal.

Ano, o tomto som pisal aj ja. V novsich verziach to prestalo chodit, tusim som to skusal iba na 0.9.2

medhi
Generous Backer | 255
+
0
-

Ola: Přesně tak to mám, bohužel to právě nefunguje.

Ola
Člen | 385
+
0
-

Zkus dát před ten {widget} (ačkoli je ve snippetu) zavináč. Mně to tak na 0.9.4 chodí.

Editoval Ola (10. 5. 2010 21:39)

Ola
Člen | 385
+
0
-

A fungují i přímo vnořené snippety. Fakt. Můžu i dát sample zdrojáky.

Mám pocit, že se fáma o vnořených snippetech vytvořila na základě „nových“ snippetů nevyžadujících zavináče – u nich to tuším nejde.

Editoval Ola (10. 5. 2010 21:39)

medhi
Generous Backer | 255
+
0
-

To mám, vypadá to takhle:

{snippet gallery}
	@{if ...}
		<div id="gallery">
			@{widget voter}
			<div class="photo">
				<img src="">
			</div>
		</div>
	@{/if}
{/snippet}

A widget vypadá takhle:

{snippet voter}
	<a class="ajax" href="{link Vote!, 1}"></a>
{/snippet}
Ola
Člen | 385
+
0
-

if tomu přidává nový level, nejsem si jistý, jestli u něj zavináče mají být či ne, ozkouším to.

Ola
Člen | 385
+
0
-

Tak mám to stejně, ale funguje mi to. Jak to invaliduješ?

Panda
Člen | 569
+
0
-

Hm, to jsou debaty… Pokud se podíváte do zdrojáku, který to má generovat, tak zjistíte, že vnořené snippety a zavináče v jejich těle mění zásadním způsobem logiku kódu. Jinými slovy – nějak to možná funguje, ale…

medhi
Generous Backer | 255
+
0
-
public function handleVote($value, $id)
{

	Votes::vote();

	if(!$this->presenter->isAjax())
	{
		$this->redirect('this');
	}
	else
	{
		$this->invalidateControl('voter');
	}

}

Když to sleduju v konzoli Firebugu, tak to vrací prádno: {"state":[]}

To vypadá, že mám někde jenom nějako blbost…

Ola
Člen | 385
+
0
-

Zkusil jsem to hodit do archivu: (PHP 5.3)

http://leteckaposta.cz/584155443

EDIT: nějak sem si tam hrál s tím invalidateControl, je možný že sem tam nechal invalidaci u presenteru, fungovat by mělo obojí

Editoval Ola (10. 5. 2010 22:18)

medhi
Generous Backer | 255
+
0
-

Už asi vím. Ten IF, který tam je, je spouštěn na základě jednoho signálu. Při invalidaci widgetu už je však signál fuč a tak se vnitřek neinvaliduje, protože se nedostane přes tu podmínku. Ovšem, jak tam ten signál udržet nebo poslat znovu, to zatím zkoumám.

medhi
Generous Backer | 255
+
0
-

A zjistil jsem, že to nemá vůbec co dělat se vnořenými snippety. Ten obalový snippet tam ani nemusí být a přesto se widget nepřekresluje. Stačí, když je umístěn v podmínce, která ho zobrazí pouze na základě nějakého signálu.

Stručně:

Presenter:

<?php
public function handleShowMe()
{
	$this->template->showMe = TRUE;
}
?>

Template:

@{if isset($showMe)}
	@{widget voter}
@{/if}

Template voteru:

{snippet voter}
	<a href="{link Vote!}">Vote</a>
{/snippet}

Pokud invaliduji widget voter, tak se widget nepřekreslí.

Dělám to nějak blbě nebo je to vlastnost nebo je to bug?

wdolek
Člen | 331
+
0
-

uff, zrovna resim neco podobneho a take jsem narazil – vysledek „thready“ by me velice zajimal… ( trhead: https://forum.nette.org/…uzit-snippet )

vytvoril jsem komponentu GalleryRecord ktera vypisuje jeden zaznam galerie. pod zaznamem je pak snippet, ktery pouziva tu samou komponentu k vykresleni pod-galerii.

vsiml sem si, ze na 1. urovni Nette vygeneruje nazvy snippetu snippet-galleryRecord-sub_17, na 2. urovni uz nazev snippetu vypada takto snippet-galleryRecord-galleryRecord-sub_18… nemuze byt problem prave v tom? (jen ma domnenka, koukal sem do zdrojaku Control a moc jsem z toho moudry nebyl, co tam probiha).
na 2. urovni taktez dostanu prazdnou JSONi odpoved :P … myslel sem, ze za to muzou ty proklate zavinace. zoufale sem pak zkusil (nehlede na thread od pandy o zavinacove magii) snad vsechny kombinace s/bez zavinacu, ale ani tuk.

GalleryRecord.php

<?php
/**
 * Gallery record control
 */
class GalleryRecord extends Control {
	/**
	 * @var \Foo\Models\Content\Gallery
	 */
	private $gallery = NULL;

	/**
	 * @var array of \Foo\Models\Content\Gallery
	 */
	private $childGalleries = NULL;

	/**
	 * @param \Foo\Models\Content\Gallery $gallery
	 * @param bool $isOdd
	 * @return void
	 * @throws \InvalidArgumentException
	 */
	public function render($gallery, $isOdd = NULL, $level = 1) {
		if (!($gallery instanceof Gallery)) {
			throw new \InvalidArgumentException('Instance of Gallery must be passed!');
		}

		$this->gallery = $gallery;

		// template
		$template = $this->template;
		$template->setFile(__DIR__ . '/GalleryRecord.phtml');

		// properties
		$template->gallery = $gallery;
		$template->galleryId = $gallery->getId();

		$template->childGalleries = $this->childGalleries;

		$template->isOdd = (bool) $isOdd;
		$template->level = max(1, intval($level));

		// render
		$template->render();
	}

	/**
	 * @return void
	 */
	public function handleSubTree($parentGalleryId) {
		$galls = Gallery::find(NULL, NULL, array(Gallery::FIELD_ID_PARENT => $parentGalleryId));

		// wrap to array
		if (!is_null($galls) && !is_array($galls)) {
			$galls = array(
				$galls->getId() => $galls
			);
		}
		$this->childGalleries = $galls;

		if ($this->presenter->isAjax()) {
			$this->invalidateControl('sub_' . $parentGalleryId);
		}
	}

	/**
	 * @return \GalleryRecord
	 */
	public function createComponentGalleryRecord() {
		return new self;
	}
}

GalleryRecord.phtml

<div class="record{if $isOdd} odd{/if}" style="margin-left: {=(($level - 1) * 30)}px;">
	...
</div>
@{if $gallery->hasChild()}
	{snippet sub_$galleryId}
		@{if $childGalleries}
			@{foreach $childGalleries as $g}
				@{widget galleryRecord $g, $iterator->isOdd(), ($level + 1)}
			@{/foreach}
		@{/if}
	{/snippet}
@{/if}
Aurielle
Člen | 1281
+
0
-

Zavináče do snippetu nepatří, viz https://forum.nette.org/…agie-v-praxi.
edit: je to jen konstatování, v ajaxu se prozatím moc nevyznám, takže je možná v tomto směru moje odpověď bezvýznamná.

Editoval gmvasek (21. 5. 2010 10:32)

wdolek
Člen | 331
+
0
-

gmvasek: jo toho sem si vedom :) jenze to nefunguje s nima i bez nich… a zde sem je radeji uvedl – zavinac prece indikuje, ze komponenta je invalidovatelna (tak sem to pochopil) – a ja chci, aby widget ve snipetu invalidovatelny byl.

Honza Kuchař
Člen | 1662
+
0
-

Projdi si kód a zjistíš, jak to funguje. Hledej SnippetHelper. Případně to bylo na nějakém videu z poslední soboty. Je tady na wiki.

wdolek
Člen | 331
+
0
-

Honza Kuchař: muzu se zeptat, kterepak je to video? skoukl sem vsechny uvadene PS, (vcetne PS o Adobe Fireworks a Enterprise Architect :D), ale nikde se problematika vnorenych snippetu neresila

do zdrojaku jsem take koukal, ale stale nic nevykoukal. v tutorialech, FAQ, ani v prirucce programatora jsem take nenasel nic konkretniho, co by resilo podobnou situaci.

Honza Kuchař
Člen | 1662
+
0
-

Myslím, že je to i někde tu na wiki, ale jisto jistě je kopie i mu mě na server: http://projekty.mujserver.net/…ardubice%29/

wdolek
Člen | 331
+
0
-

aha, tak zrovinka tyhle videa sem si z nejakeho duvodu nestahl :'( :) no uz je mam, diky ;)

wdolek
Člen | 331
+
0
-

Honza Kuchař: tak abych pravdu rekl, nejak mi to k reseni meho problemu nepomohlo… ze mohu includnout sablonu samu v sobe je sice pekne, jenze – vytvoreni Controlu se sablonou, v ktere je snippet, ktery vytvari novou instanci toho sameho Controlu (widgetu), ktery pouziva tu samou sablonu… … a ktery se pak ajaxove invaliduje… to nejak nevyresilo :(


… a protoze to asi nedovedu poradne vysvetlit, tady je videjko: http://storage.wdolweb.cz/…_snippet.ogv

  • prvni AJAXovy dotaz dostane odpoved,
  • druhy AJAXovy dotaz uz odpoved nedostane (neprovede se invalidace – payload neobsahuje pole snippetu, ktere se maji prekreslit (a obsah prekresleni))

GalleryRecord reprezentuje jeden radek v tabulce (jeden zaznam, jednu galerii).

handler controlu GalleryRecord:

	public function handleSubTree($parentGalleryId) {
		$galls = Gallery::find(NULL, NULL, array(Gallery::FIELD_ID_PARENT => $parentGalleryId));

		// wrap to array
		if (!is_null($galls) && !is_array($galls)) {
			$galls = array(
				$galls->getId() => $galls
			);
		}
		$this->childGalleries = $galls;

		if ($this->presenter->isAjax()) {
			$this->invalidateControl('sub_' . $parentGalleryId);
		}
	}

sablona controlu (2. – N. uroven):

<!-- vypis radku v <div> ... -->
...

<!-- snippet, pokud ma galerie decka -->

@{if $gallery->hasChild()}
	{snippet sub_$galleryId}
		{if $childGalleries}
			{foreach $childGalleries as $g}
				{widget galleryRecord $g, $iterator->isOdd(), ($level + 1)}
			{/foreach}
		{/if}
	{/snippet}
@{/if}

sablona, ktera zobrazuje seznam galerii (1. (korenova) uroven):

<ul class="list">
@{foreach $galleries as $g}
	<li>
		@{widget galleryRecord $g, $iterator->isOdd()}
	</li>
@{/foreach}
</ul>

zkusil sem vypnout uplne JS – a skutecne neni chyba nekde v generovani jmena snippetu? ackoliv vse v HTML a controlu sedi (zkousel sem si vypsat getSnippetId(...), dostavam odkazy:

odkaz na korenove galerii pro zobrazeni pod galerii:
?galleryRecord-parentGalleryId=17&language=cs&do=galleryRecord-subTree

odkaz na druhou uroven galerii, pro zobrazeni 3. urovne:
?galleryRecord-galleryRecord-parentGalleryId=18&language=cs&do=galleryRecord-galleryRecord-subTree

a ackoliv v HTML je snippet pojmenovan snippet-galleryRecord-galleryRecord-sub_18 tak je zvlastni to zdvojeni nazvu controlu – galleryRecord-galleryRecord-subTree – kdyz zkusim tuto akci spustit neAJAXove, dostanu akorat vynadano… neni prave toto ten duvod, proc nedostavam zadnou odpoved? (na druhou stranu to ale nehaze ani zadnou 500)

Editoval wdolek (24. 5. 2010 23:44)

Gaprielko
Člen | 42
+
0
-

wdolek: Riesim podobny problem ako ty a tiez mam rovnaky problem s invalidovanim snippetu druhej urovne., podarilo sa ti ten problem uz medzicasom vyriesit??