Komponenty, persistentní parametry a funkční ukázka (po X-té)

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

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 VisualPaginatoru je persistentní parametr $page.

Ve FilterFormu 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)

enumag
Člen | 2118
+
0
-

Ten FilterForm dědí Form nebo Control? Asi Control když má perzistentní parametr…?

Tyhle věci pokud vím dělají v metodě attached té komponenty.

Editoval enumag (7. 1. 2015 14:30)

joe
Člen | 313
+
0
-

FilterForm dědí od Control. V attached mi to nejde, protože tam má parametr svou výchozí hodnotu. Zkusím udělat příklad.

jiri.pudil
Nette Blogger | 1032
+
0
-

Voláš v attached nejdřív parent::attached? Tam se právě do těch parametrů dostanou přijatá data.

enumag
Člen | 2118
+
0
-

Srry, metoda loadState.

joe
Člen | 313
+
0
-

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 nebo loadState 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
+
0
-

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
+
0
-

Je tam přesně to, co potřebuju, ale jak to prosím dostat do toho formuláře? :) (ale objeví se to tam až ve chvíli, kdy formulář odešlu a teprve potom kliknu na další stránku.

enumag
Člen | 2118
+
+1
-

Normálně $form->setDefaults([ ... ]);, ne? ;-)

joe
Člen | 313
+
0
-

Tak problém u mě, místo setDefaults jsem psal setValues… Díky moc za vyřešení problému. Doplním sem komplětní příklad :-)

joe
Člen | 313
+
0
-

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
+
0
-

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
+
0
-

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.

enumag
Člen | 2118
+
0
-

@joe Normálně otestuj jestli ten perzistentní parametr s filtrem je NULL – když ne zobrazíš tlačítko. Nebo mi něco uniklo?

joe
Člen | 313
+
0
-

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.