Změna šablony komponenty s attached na presenter

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
kleinpetr
Člen | 480
+
0
-

Ahoj,

mám komponentu, která se připojuje na presenter pomocí attached() když chci ale v nějakém presenteru změnit šablonu té komponenty na nějakou konkrétní, tak mi hlásí, že komponenta nebyla připojena k presenteru.

Jak se dá tedy řešit změna šablony zároveň s attached() Díky

Editoval kleinpetr (1. 6. 2015 12:27)

enumag
Člen | 2118
+
0
-

Např. tak že v továrně té komponenty zavoláš

$component->setParent($this);

V tu chvílu už bude komponenta připojená. (EDIT: Možná musíš předat ještě $name aby to fungovalo správně.)

Osobně jsem si (z jiných důvodů) ke komponentám přidal událost onAttached, což je druhá možnost jak řešit tvůj problém.

Editoval enumag (1. 6. 2015 12:47)

akadlec
Člen | 1326
+
0
-

Já bych řek že se snaží na tu komponentu šahat ještě dříve než se připojí k presenteru. Tohle mi dělalo když jsem v attached přistupoval presenteru, ale došlo k volání ježe v továrně. Stačilo upravit body přístupu ke komponentě a je to ok.

kleinpetr
Člen | 480
+
0
-

@akadlec Pravděpodobně máš pravdu, zkrátka v createComponentNeco() se vytvořím komponentu a chci jí změnit šablonu. Co máš na mysli tím upravit body přístupu ? díky

enumag
Člen | 2118
+
0
-

Tzn. používáš $component->getTemplate()->setFile(...) že? Osobně to řeším tak že jsem si přidal property a volám $component->setTemplateFile(...), komponenta tu hodnotu později předá šabloně.

Editoval enumag (2. 6. 2015 8:09)

kleinpetr
Člen | 480
+
0
-

No mám to zkrátka takhle

V komponentě:

protected function attached($presenter)
{
    parent::attached($presenter);

    if ($presenter instanceof Presenter) {
        $this->translator = $presenter->translator;
    }
}

V presenteru:

protected function createComponentMyComponent()
{
    $component = $this->someComponent->create();
    $component->template->setFile('other.latte');

    return $component
}

tohle vrátí chybu:
Component '' is not attached to 'Nette\Application\UI\Presenter'

akadlec
Člen | 1326
+
0
-

No to je to co ti zmiňuje enumag, jen tedy on použil getter a ty magickou metodu.

kleinpetr
Člen | 480
+
0
-

Jojo vím.

Vyřešeno takto:

v komponentě:

	protected $templateFile = 'componentDefault.latte';

public function setTemplateFile($file)
{
    $this->templateFile = $file;
}

public function render()
{
    /** @var Nette\Bridges\ApplicationLatte\Template $template */
    $template = $this->template;

    $template->setFile(__DIR__ . '/templates/'.$this->templateFile);
	}

Díky za pomoc.

newPOPE
Člen | 648
+
0
-

@kleinpetr

  1. Presenter nema co menit sablonu komponenty na to mas render* v komponente
  2. Ked uz to potrebujes tak to nerob vo factory metode ale v action*, render* metode presenteru (zbavis sa attached problemu tym padom aj tohto $this->translator = $presenter->translator; a vyriesi ti to DI)
akadlec
Člen | 1326
+
0
-

To bych si dovolil nesouhlasit. Vytvoříš jednu komponentu, ale budeš ji chtít použít na dvou místech (presenterech) ale pokaždé bude vypadat jinak. Takže přesenter přes setter nastaví jakou šablonu má komponenta použít. Dělat to v render metodě nějakou magii je imho špatně.

A ad translator, jo může si jej předat pomocí constructoru, ale zase třeba když používá kdyby/translator tak si určí prefix který chce mít společný s presenterem tak si jej z presenteru vytáhne ;)

newPOPE
Člen | 648
+
0
-

Tak sa skusme zamyslet.

Povedzme, ze 2 miesta su 2 presentery. Tym padom nebudem pisat 2 rozne factory metody ale budem mat jednu niekde v predkovi (napr. BasePresenter daneho modulu ak nejaky mam). No a tu pride na rad tvoja magia ;) nakolko podla coho factory metoda vyhodnoti aky template ma nastavit?.

Ja uprednostujem trocha iny pristup (ked uz to musi byt) a to:

// factory method
public function createComponentMyComponent() {
	return $this->myComponentFactory->create();
}

// konkretny presenter A
public function renderFoo() {
	$this['myComponent']->setTemplateFile('foo.latte');
}

// konkretny presenter B
public function renderBar() {
	$this['myComponent']->setTemplateFile('bar.latte');
}

Co nevybocuje od toho co pises nakolko to nastavuje konkretny presenter.

No a keby velmi chcel tak sa na sablony v Presenteri vykasle lebo tie by mohol ovladat View (za predpokladu, ze pri view uz vynimka nevyleti na co treba mysliet pri pisani) a to takto:

// viewPresenteru.latte (tento example ma problem s Ajaxovanim komponent!)
{control myComponent:foo}
{control myComponent:bar}

Editoval newPOPE (2. 6. 2015 11:50)

akadlec
Člen | 1326
+
0
-

No a teď to zajaxuješ a budeš v prdeli protože nette nebude vědět jakou šablonu použít a použije defaultní renderer

newPOPE
Člen | 648
+
0
-

Presne toto som cakal :D.

Ano mas pravdu (schvalne som to nespominal). To je skor na debatu o Ajaxovani komponent…

enumag
Člen | 2118
+
0
-

Přesně jak píše @akadlec. Šablonu nastavuju zásadně už v presenteru. (Respektive nastavuju view s tím, že TemplateLocator podle něj najde šablonu, ale to je detail.)

kleinpetr
Člen | 480
+
0
-

Takže pokud jsem to pochopil správně..

ten translator si můžu normálně předat v konstruktoru té komponenty přes DI ? :)

newPOPE
Člen | 648
+
0
-

Samozrejme, na to DI je.

kleinpetr
Člen | 480
+
0
-

Akorát teď nevím, zda v konstruktoru předávat (Translator $translator) nebo (ITranslator $translator)

Azathoth
Člen | 495
+
0
-

no, čistší by bylo předávat ITranslator, ale v praxi stejně implementaci nevyměňuješ, takže je to jedno.

kleinpetr
Člen | 480
+
0
-

Můžeš to prosím trochu rozvést ? :) děkuju

newPOPE
Člen | 648
+
0
-

Ide o to, ze ked tam uvedies Translator co je rovno trieda aj s implementaciou tak si v podstate zatvoris dvere pre zmenu. Napriklad ked to budes chciet vymenit za MySuperCoolTranslator a tento translator nebude potomok Translator-u tak ti to neprejde type checkom a budes to musiet prepisat vsade.

Ked pouzijes ITranslator tak uvedies len rozhranie (interface) a vtedy len staci aby dany translator implementoval toto rozhranie. Type check je v poriadku lebo ocakava instanciu ITranslator-u. Cize vymena je easy nakolko ked budes menit Translator tak len v novej implementacii implementujes dany interface.