Komponenty, persistentní parametry a funkční ukázka (po X-té)
- joe
- Člen | 313
Ahoj, zkouším opět proniknout trochu do Nette, jako uživatel a využívat jeho možností. Bohužel po prozkoumání plno diskusí, slabé (alespoň v tomto tématu) dokumentace jsem nedošel k nějakému dobrému výsledku, jak jednoduše postupovat.
Na stránce chci mít seznam položek, které budu moci filtrovat a stránkovat. Chci vidět změny v URL (aby se dala zkopírovat), chci používat persistentní parametry.
V Presenteru mám:
- injectovaný model, kterým chci vybírat položky
- továrničku na stránkování (
VisualPaginator
) - továrničku na filtrační formulář (
FilterForm
)
Ve VisualPaginator
u je persistentní parametr
$page
.
Ve FilterForm
u je persistentní parametr $values
jako pole. V callbacku onSuccess
persistentní parametr nastavuji
hodnotama formuláře, nepřesměrovávám, formulář je posílán GET
metodou.
Otázka je, kde přesně mám nastavit hodnoty (z persistentního parametru) zpátky do formuláře? Po změně filtračního formuláře jsou persistentní parametry správně u odkazů na další stránku, ale při kliknutí na ni už se mi do formuláře nepředvyplní. Nevím jak je je mám tomu formuláři nastavit… :)
Rád bych touto diskusí pomohl všem, co budou řešit podobný problém, nejprve bych začal spíš postupem (textem, pseudokódem) a ve finále konkrétním použitelným kódem.
Editoval joe (7. 1. 2015 14:21)
- jiri.pudil
- Nette Blogger | 1032
Voláš v attached
nejdřív parent::attached
? Tam
se právě do těch parametrů dostanou přijatá data.
- joe
- Člen | 313
Zkoušel jsem i loadState, i když pořádně nevím, k čemu ta metoda přesně je a kdy se volá, bez prozkoumání zdrojáků přímo v Nette to asi nezjistím.
Napsal jsem rychlý případ, jak podobně to mám, není tam řešené DI s
„dnešní best practice“ s využitím interface
.
<?php
// --- Nejaky ukazkovy presenter ---
class DemoPresenter extends BasePresenter
{
function actionDefault()
{
$visualPaginator = $this->getComponent('visualPaginator');
$paginator = $visualPaginator->getPaginator();
$paginator->setItemsPerPage(20);
$paginator->setItemCount(80);
}
public function createComponentFilterForm()
{
return new FilterForm();
}
public function createComponentVisualPaginator()
{
return new VisualPaginator();
}
}
// --- Komponenta pro FilterForm ---
class FilterForm extends \Nette\Application\UI\Control
{
/** @persistent */
public $name = '';
public function render()
{
// sablona pro komponentu, obsahuje jen vyrendrovani formulare {control form}
$this->template->setFile(__DIR__ . '/default.latte');
$this->template->render();
}
protected function createComponentForm()
{
$form = new \Nette\Application\UI\Form;
$form->setMethod('get');
$form->addText('name', 'Název:');
$form->addSubmit('filter', 'Filtruj');
$form->onSuccess[] = $this->process;
return $form;
}
public function process(\Nette\Application\UI\Form $form)
{
// nastavi persistentni parametry podle hodnot z formulare
$values = $form->getValues();
foreach($this->getPersistentParams() as $pp) {
if (isset($values[$pp])) {
$this->{$pp} = $values[$pp];
}
}
}
}
- při prvním načtení jsou odkazy stránkovače správné (zahrnují persistentní parametr page)
- po vyfiltrování (vyplnění a odeslání formu) jsou odkazy u stránkování taky dobře, je vyplněn persistentní parametr page a zároveň parametr name.
- kliknutím na další stránky persistentní parametry zůstávají,
ale dojde ke smazání hodnoty z formuláře. Zkoušel jsem
přepsat
attached
neboloadState
v komponentě FilterForm tímto kódem (?), ale pak mi to přestalo fungovat úplně
$form = $this->getComponent('form');
$form->setValues(array(
'name' => $this->name,
));
- a to tak, že po odeslání formuláře se mi v inputu neobjeví vůbec nic
a parametr
name
zůstal na své výchozí hodnotě…
- enumag
- Člen | 2118
Metoda loadState dostává argument. Schválně si ho dumpni, mělo by tam být to co potřebuješ.
Jo a hlavně nezapomeň zavolat parent::loadState($params);
.
Pokud tohle zavoláš před svým kódem tak by mělo fungovat i to
$this->values
(nebo jak se jmenuje ten parametr).
Editoval enumag (7. 1. 2015 15:25)
- joe
- Člen | 313
Ještě by mě zajímalo, jak mám po odeslání skočit na první stránku? Pokud jsem třeba na stránce 3, chci něco vyfiltrovat, zůstanu na stránce 3.
Možná bych čekal, že když pers. parametry nastavím a pak provedu
přesměrování, z komponenty asi jednoduše
$this->presenter->redirect('default');
tak že se zachovají,
ale dojde k jejich vyrušení… Nebo jak by to šlo udělat nějak
elegantně?
- Zax
- Člen | 370
Persistentní parametry se zachovávají pouze u té komponenty, na které provádíš přesměrování. Presenter neví/neřeší, jaké persistentní parametry jsou v jaké komponentě, takže je vyruší.
Co zkusit něco jako
$this->redirect('this', ['page' => 0])
kde page
je persistentní parametr v té komponentě? To by mělo nastavit stránku na
nulu a zároveň zachovat ostatní parametry.
Editoval Zax (7. 1. 2015 17:00)
- joe
- Člen | 313
Díky, to pomohlo, stačilo tedy dát do komponenty FilterForm (konkrétně
do process()
) přesměrování
$this->redirect('this');
. Persistentní parametr pro stránku je
v jiné komponentě, dojde k vyrušení. Tím se mi ihned po odeslání
formuláře s filtrem přesměruje (možná zbytečné přesměrování (?)).
Teď si ještě trochu lámu hlavu s tim, že bych chtěl přidat do
formuláře tlačítko na zrušení filtru, ale jednoduše nevím jak poznám,
že ho tam mám zobrazit. $form->isSubmitted()
mi teď
nepomůže.
- joe
- Člen | 313
Tak to jde, nebylo by čistější ale mít pro každou tu položku formuláře persistentní parametr? Nevím (neznám to uvnitř), jestli by to znamenalo větší zátěž.
Při více položkách ve formuláři mi pak vzniká dlouhá URL
?filter-filter[‚name‘]=jmeno&filter-filter[‚country‘]=zeme
Při každém persistentním parametru bych měl jenom
?filter-name=jmeno&filter-country=zeme
A to bych pak pro zobrazení tlačítka musel otestovat, jestli nějaký persistentní parametr nemá výchozí hodnotu, abych ho zobrazil… ale jinak to asi nepůjde.