Filtrovací formulář + AJAX + stránkování
- joe
- Člen | 313
Ahoj,
potřeboval bych poradit, jak udělat formulář, kterým budu filtrovat pomocí AJAXu a následně filtrované položky budu moci stránkovat.
Nepoužívám komponentu, vše mám v presenteru, kde je továrnička na formulář (metoda GET), na Paginator. Filtrování mi v současné době funguje, ale jakmile kliknu na další stránku na paginatoru, tak se mi nepoužijí ty hodnoty z filtrování, takže sice se položky stránkují, ale ne vyfiltrované.
Zajímalo by mě tedy, kam a jak mám ukládat ty hodnoty z filtrování?
Zkoušel jsem se dívat do DataGridu, ale nějak to z toho nemůžu vyčíst,
ještě se v tom tolik neorientuji.
Zkoušel jsem dát perzistentní parametry do presenteru, ale odkazy
stránkovače jsou pořád ve tvaru:
…?paginator-page=2
Díky moc za rady
- joe
- Člen | 313
Tak posílám kód, dost jsem to zjednodušil, ale jinak to mám stejně:
<?php
class MyPresenter extends BasePresenter {
/** @persistent string */
public $filter = '';
public function renderDetail() {
$form = $this['filterForm'];
// rozpoznani, jestli byl form odeslan a podle toho vyber polozek
$items = Items::get();
// pokud by byl formular odeslan, tak bych do atributu $filter ukladal hodnoty z formulare ve tvaru URL: ...¶m1=value¶m2=value
// a protoze je perzistentni, ocekaval bych to pak i u tech odkazu v paginatoru
if($this->isAjax()) {
$this->invalidateControl('items');
$this->invalidateControl('paginator');
}
}
}
?>
A v šabloně mám jen jednoduchý výpis:
{control formFilter}
{snippet items}
{foreach $items as $item}
...
{/foreach}
{/snippet}
{snippet paginator}
{control paginator}
{/snippet}
Editoval joe (20. 2. 2011 3:54)
- joe
- Člen | 313
Tak samozřejmě má chyba, přehlédl jsem, že nenastavuji ten
perzistentní parametr u všech vlastností a pak jsem to filtroval
jinými.
Teď se tam už vkládá.
Ale co mi zase vadí je to, že u všech odkazů vedoucí do samého presenteru budou ty perzistentní parametry. Odkazy na detaily bych chtěl mít jen …/detail/4
No zkrátka s tím, co se mi teď ukládá do $filters
bych
chtěl mít odkazy jen v Paginatoru, nikde jinde.
Nebo by to šlo celé udělat nějak jinak – lépe? Prosím o nakopnutí…
- bojovyletoun
- Člen | 667
Informace o frázi a o stránce se přece musí někde uchovávat? Jedna
z možnostní jr právě URL.
Duhá možnost je v session – mě napadlo k tomu účelu použít metody
loadstate a savestate u komponenty – podrobněji zde
jinak jsem to v praxi nerealizoval.
EDIT: realizoval jsem první část s kódem. Ta druhá od „jak to
vylepšit“ je ten nápad, co jsem zde popisoval.
Jo ještě nezapomeň po změně hledaného výrazu nastavit první stranu.
Editoval bojovyletoun (20. 2. 2011 12:50)
- joe
- Člen | 313
Právě bych tu informaci chtěl přenášet u odkazů, ale jen u těch, co jsou v paginatoru. Nechtěl bych do toho tahat sessions, už z toho důvodu, že používám schválně GET pro neAJAXové požadavky, aby bylo možné zkopírovat adresu. S AJAXem bude použitý #.
Pro představu:
Mám presenter ItemPresenter, v renderDefault()
vypisuju
všechny položky, v renderDetail($id)
detail jen jedné.
Takže u odkazu na detail v šabloně {plink detail 5}
, bych
chtěl, aby pořád zůstal
../detail/5
a nepřidával parametry s filtrováním, protože je tam stejně nevyužiju, akorát se tím kazí jednoduchá adresa. V případě stránkování ale chci, aby tam byly (jinak by to ani nešlo):
../?do=formFilter-submit¶m1=value¶m2=value&…
V případě těch persistentních se tam ale přidají, což je správné, ale nechtěné. Je možné nějak ty parametry resetovat nebo nějak nastavit, aby se u některých odkazů negenerovaly?
loadState & saveState
K ukládání stavu jsem se včera taky dostal, ale moc jsem nepochopil jak na
to. Mj. jsem na fóru četl, že to z presenteru bylo odstraněno (ale byl to
starý příspěvek), nicméně teď to u něj mám. Zkoušel jsem metodu
saveState()
, která nevím proč, ale zavolá se aspoň 6×.
Editoval joe (20. 2. 2011 13:35)
- joe
- Člen | 313
Tak dalo by se to vyřešit tak, že si do Paginatoru přenesu ty parametry, které tam chci mít. Zároveň bych ale chtěl, aby se po kliknutí na odkaz v něm odeslal i formulář, parametry se ale dávají do URL s prefixem paginatoru:
?paginator-page=5&paginator-do=formFilter-submit
a já bych potřeboval
?paginator-page=5&do=formFilter-submit
To by nějak vyřešit šlo?
- Ani
- Člen | 226
Jestli máš te řetězec hodně dlouhej, tak si z něj můžeš parametry
pro filtr někam ukládat, dělat z toho hash a ten dávat do url. Pak jen
načteš filtr podle řetězce (hashe). Docílí se tím toho, že ta url nebude
mít třeba několik set znaků.
Jinak co píšeš pak dál mi není moc jasný, to jednou chceš zpracovat
formulář jako POST a jidny zas předávat jako GET.
- joe
- Člen | 313
Udělat z hodnot parametrů hash? A jak se ty hodnoty pak dozvim? :-) Uvítám nějaké zkrácení odkazu, asi jsem nepochopil jak jsi to myslel.
Vysvětlím to trochu podrobněji. Snad to pak bude úplně jasné.
Mám ItemPresenter
s renderDefault
(výpis všech
položek) a renderDetail($id)
(výpis konkrétní). Na výpisu
všech položek mám filtrovací formulář, kde je možné změnit cca. dvacet
hodnot.
Filtrovací formulář se vždy bude posílat metodou GET. Bez AJAXu dostanu správnou URL a s AJAXem budu měnit část za #.
Odkazy na detaily jednotlivých položek chci mít:
/item/detail/3
ne takto:
/item/detail/3?do=formFilter-submit¶m1=value¶m2=value¶m3=value&...
S tím, že odkazy v Paginatoru musí být právě:
/item/?paginator-page=2&do=formFilter-submit¶m1=value¶m2=value¶m3=value&...
protože při stránkování potřebuji vědět, podle čeho se filtruje.
Tzn., že musím při kliknutí na další stránku docílit odeslání
formuláře. Při {action}Default
totiž kontroluju jeho odeslání
a následně na to vybírám položky z modelu (db).
Potřeboval bych nějaké jednoduché a funkční řešení. Proto mi přijde zbytečné ukládat si parametry jinam, když je pokaždé dostávám v URL adrese.
Zatím to asi vyřeším tak, že v Paginatoru si dám nějaký atribut
public $filter
, který budu předávat do jeho šablony a tam
odkazy vypisovat
<a href="{link this, 'page' => $paginator->page + 1}{$filters}">Další stránka</a>
a v presenteru ItemPresenter, konkrétně v renderDefault budu paginatoru nastavovat tu hodnotu $filters.
Možná to nebude nejlepší řešení, ale jiné mě nenapadá. Jakékoli další rád uvítám.
- Filip Procházka
- Moderator | 4668
$q = &$presenter->request->params['q'];
# nebo z persistentniho parametru
$session = $this->getSession('FilterQuery');
// save
$q = substr(md5(serialize($arrayOfṔarams)), 0, 6);
$session[$q] = $arrayOfParams;
# nezapomenout předávat v query
// read
$arrayOfParams = $session[$q];
Editoval HosipLan (20. 2. 2011 15:47)
- joe
- Člen | 313
Jó díky, vůbec mi to nedocvaklo s tím hashem, jak to bylo myšlené. Asi toho ještě využiju, ještě zvážím, možná to je taky zbytečné, protože pak se zase nemůžou jednoduše hodnoty v URL přepisovat.
Nakonec jsem to teda vyřešil nějak takhle. Asi to má nějaké mouchy, ale u mě se to zdá být funkční. Do paginatoru si předám to $filters, které generuju z požadavku.
<?php
public function loadState(array $params) {
parent::loadState($params);
$filters = '';
foreach($params as $param => $value) {
if($param == 'action' || $param == 'id') continue;
if(!is_array($value)) {
$filters .= '&' . $param . '=' . $value;
} else {
foreach($value as $k => $v) {
$filters .= '&' . $param . '[' . $k . ']=' . $v;
}
}
}
$this['paginator']->filters = $filters;
}
?>
EDIT: ještě je třeba dodělat kontrola, jestli jsou ty parametry v tom formuláři nebo to raději brát přímo z toho formu.
Editoval joe (20. 2. 2011 16:06)
- joe
- Člen | 313
Ještě poznámka – je na to ale třeba myslet při routách, kdyby se ten parametr paginator-page nějak zkracoval, tak aby ty filtry začínaly otazníkem.
Nebo vás napadne ještě nějaké jiné / lepší řešení jak toho docílit?
Díky moc za odpovědi
EDIT: Mi neříkejte, že ještě nikdo neřešil něco podobného…
Editoval joe (20. 2. 2011 22:51)