Problém s předáváním parametrů render metodě komponenty při překreslení snippetu v komponentě

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

Zdravím,
mám v latte komponentu:

{control emailShareComponent-2 center => TRUE, gaCategory => 'myCategory', gaAction => 'myAction'}

V komponentě je formulář, který se odesílá ajaxově (kvůli hezkým chybovým hláškám).

{snippet form}
	{form emailShareForm class => 'ajax '}
		{* ... *}
		<button n:name="submit" type="submit" class="sendGaEvent" data-ga-category="{$gaCategory}" data-ga-action="{$gaAction}">{_front.form.submit}</button>
	{/form}
{/snippet}

Problém je, že renderování snippetu „form“ při odpovědi na ajaxový požadavek mi skončí s exception ‚Undefined variable: gaCategory‘. Jak to provést, aby to takhle fungovalo? Při renderování to předávám komponentě proto, že se stejná komponenta používá napříč celým frontendem s různými parametry. Lepší způsob mě momentálně nenapadá. Zjevně mi ale uniká nějaká souvislost mezi fungováním snippetů a předáváním parametrů ze šablony presenteru. Za nakopnutí budu ráda.

Edit: v komponentě mám:

public function render(array $data = [])
	{
		# template
		$template = $this->reflection->shortName;

		$this->template->setFile(__DIR__ . '/' . $template . '.latte');

		# template vars
		foreach($data as $name => $value){
			$this->template->$name = $value;
		}

		// ...

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

Render metoda se při ajaxu zavolá, ale pole $data je prázdné.

Editoval chikeet (31. 10. 2015 16:20)

F.Vesely
Člen | 369
+
0
-

Jde o to, ze se pri pozadavku komponenta pouze vytvori (zavola se metoda createComponentXXX()) a pak se prekresli jen snippet a ne presenter. Reseni je, ze si ty parametry budes predavat v konstruktoru te komponenty.

vitkutny
Člen | 73
+
+2
-

pokud jsou parametry povinné, vyžaduj je vždy v konstruktoru komponenty, dle toho vytvoř několik createComponent metod, případně zkombinuj pomocí multiplieru

protected function createComponentCenteredEmailShareComponent(){
	return new Multiplier(function($gaCategory){
		return new Multiplier(function($gaAction) use($gaCategory){
			$control = new EmailShareComponent($gaCategory, $gaAction);
			$control->setCentered();

			return $control;
		});
	});
}
\—
použití v šabloně
{control centeredEmailShareComponent-gaCategory-gaAction}
\—
pokud je centrování provedeno mimo snippet, je možné využít samostatnou šablonu

/—html
{control emailShareComponent-gaCategory-gaAction:centered}
\—

nicméně pokud to jde tak zrovna centrování bych nedával do komponenty a tam kde má být centrovaná bych obalil divem s odpovídající třídou

/—-html
<div class=“centeredEmailShareComponent”>
	{control emailShareComponent-gaCategory-gaAction}
</div>
vitkutny
Člen | 73
+
+3
-

pokud chceš aby ajax fungoval vždy správně vyhni se předávání jakýkoliv závislostí “zvenčí" (i používání renderXxx()), vždy nachystej druhou metodu (nebo využívej Multiplier, případně kombinace) createComponent pro vytoření komponenty, kde nastavíš vše jak potřebuješ

ic
Člen | 430
+
0
-

A ještě si říkám, jestli jsou ty formuláře odesílány ajaxově jenom kvůli hezkým chybovým hláškám, dá se to udělat i bez toho. Metoda Nette.addError ( https://github.com/…etteForms.js#L235 ) je pěkně psána tak, že se dá ‚přetížit‘ a místo alertování může dělat nějaký o kus krásnější efekt. Jako výpis do flash zpráviček nebo do nějakého elementu před/za ten který formulářový prvek.

chikeet
Člen | 160
+
0
-

ic napsal(a):

A ještě si říkám, jestli jsou ty formuláře odesílány ajaxově jenom kvůli hezkým chybovým hláškám, dá se to udělat i bez toho. Metoda Nette.addError ( https://github.com/…etteForms.js#L235 ) je pěkně psána tak, že se dá ‚přetížit‘ a místo alertování může dělat nějaký o kus krásnější efekt. Jako výpis do flash zpráviček nebo do nějakého elementu před/za ten který formulářový prvek.

To zní dobře. Je to určeno jen pro jednoduchou js validaci, nebo by se tam dala nějak rozumně ajaxově rozjet i server-side validace? To je totiž hlavní důvod současného řešení.

ic
Člen | 430
+
0
-

chikeet napsal(a):

To zní dobře. Je to určeno jen pro jednoduchou js validaci, nebo by se tam dala nějak rozumně ajaxově rozjet i server-side validace? To je totiž hlavní důvod současného řešení.

Nevím teď jestli jsme se dobře rozuměli… každopádně běžné nette formuláře, když je používám nějak takto:

	$form->addText(self::COLUMN_USERNAME, 'Email:')
		->setType('email')
		->setAttribute('maxlength', 255)
		->setRequired('Vyplň svůj email.')
		->addRule(Form::EMAIL, 'Musíš zadat platnou emailovou adresu.');

	$form->addPassword(self::COLUMN_PASSWORD, 'Password:')
		->setAttribute('pattern', '^.{4,}$')
		->setRequired('Zapomněl jsi zadat heslo.')
		->addRule(Form::NOT_EQUAL, 'Heslo nesmí být stejné jako tvůj email', $form[self::COLUMN_USERNAME])
		->addRule(Form::MIN_LENGTH, 'Heslo musí mít alespoň %d znaky', 4);

tak se automaticky validuje serverová část a navíc se generují data- atributy pro klientskou validaci pomocí netteForms.js (pokud si ho tedy člověk naincluduje do stránky).

( ->setAttribute('pattern', '^.{4,}$') je akorát pro html5 validaci bez nette, v podstatě duplicita k ->addRule(Form::MIN_LENGTH, 'Heslo musí mít alespoň %d znaky', 4) akorát to bude pracovat i klientům bez JS )

A já měl za to, že problém je v tom, že netteForms.js nedělají příliš přívětivé varování (běžný javascriptový alert). Ale naštěstí se dají (aniž by musel člověk netteForms.js hackovat a něco tam přepisovat) přetížit a ty hlášky si vypisovat někam do formuláře, což je takové uživatelsky přívětivější.

chikeet
Člen | 160
+
0
-

@ic Šlo mi spíš o složitější validace, kde potřebuju po odeslání formu něco ověřit na serveru apod. Hlavně se mi to nechce řešit nadvakrát, jednou pro js validaci a podruhé pro tu po odeslání. Takže ajax tam řešit stejně musím, protože tyhle věci do js asi nemá smysl cpát. Každopádně ale díky za přínosné info :-)