ublaboo/datagrid: mocný, rychlý, rozšiřitelný, hezký, anglicky dokumentovaný datagrid
- japijana
- Člen | 11
@PavelJanda / keď je column hidden, tak predpokladam, že ho user
nechce editovat, teda by sa mala prenasat jeho aktualna hodnota priamo, alebo
pri spracovani z $values
odstranit tento column(vsetky ktore su
hidden), nakolko ked sa nahradi prazdnym stringom tak sa edituje spolu
s ostatnymi columns bez toho aby o tom user vedel.
Editoval japijana (7. 7. 2016 9:56)
- exquis
- Člen | 83
ahoj, tak problém byl jinde – snažil jsem se používat setDefaultSort na sloupce, které jsem nevypisoval, takže se omlouvám ;)
Pavel Janda napsal(a):
Pardon, byl jsem od pc pár dní pryč, tak pojďme na to.
@exquis
1, Úplně nevím, kdy tato situace může nastat. Mohl bys připravit sandbox, kde by se toto chování projevovalo? Nebo na to narazil ještě někdo jiný? Jakou verzi datagridu používáš?2, Vím, o co se jedná. Ano pravda, nemuselo by to házet exception. Stačilo by unsetnout hodnotu ze session. Píši si.
@Hlava
Jakou verzi používáš? Na webu dokumentace (ublaboo.org) to jede v pohodě, pokud dobře chápu tvojí situaci.@japijana
Jaké jiné chování tě napadá? Nevím, zda by se vůbec měl pár klíč-hodnota odstranit z odeslaných$values
. Ty jsi tam ten klíč vytvořil při registrace formulářového pole, tedy by se to tam mělo objevit.
- David Grudl
- Nette Core | 8218
Hlásím, že verze 4.4.0 běží a lze instalovat úplně v pohodě pod Nette 2.4. 👍🏻
- pitr82
- Člen | 121
@PavelJanda Ahoj,
mám dotaz na group-actions.
$grid->addGroupTextAction('Add note')
Můžu nějak upravit atributy textového pole ?
Popřípadě šlo by požít i textarea (
$grid->addGroupTextAreaAction('Add note')
a pomocí class upravit velikost, pokud bych potřeboval poslat delší text?
Dík za odpověď
- Pavel Janda
- Člen | 977
@pitr82 Ahoj. Nope, teď to nelze. Ale vždycky můžeš poslat PR. :)
A nebo založit issue, no..
- Pavel Janda
- Člen | 977
Přídána textarea u group actions, přidány volitelné class a jiné attributy u všech group acitons, viz http://ublaboo.org/…group-action#…
@pitr82, @DavidKregl
- w3m
- Člen | 4
@PavelJanda narazil jsem na stejnou chybu jako v https://github.com/…rid/pull/206, je to již opravené? Nebo něco dělám špatně? Díky!
- Pavel Janda
- Člen | 977
@w3m Mělo by to být ok již od začátku března (ze kdy je zmíněný PR). Jakou používáš verzi?
- w3m
- Člen | 4
Zkoušel jsem 4.6 i mastera. Ve chvíli, kdy ajaxově řadím záznamy, vše funguje v pořádku, ale v URL mi zůstane:
?grid-grid-sort%5BfullStreet%5D=ASC
A po refreshi stránky dostávám chybu:
[Semantical Error] line 0, col 64 near 'fullStreet A': Error: Class App\Model\Entities\Business\Customer has no field or association named fullStreet
Datagrid:
$grid->addColumnText('fullStreet', 'Adresa')->setSortable()->setSortableCallback(function(QueryBuilder $qb, $sort) {
$qb->orderBy('i.street', $sort['fullStreet'])->addOrderBy('i.number', $sort['fullStreet']);
});
Po implementaci kódu z pull requestu mi funguje vše v pořádku.
- w3m
- Člen | 4
Ano, používám :) Nevím, jestli není problém, že první argument addColumnText() u mě není sloupec v databázi – v tuhle chvíli mám pro něj pouze getter a nastavil jsem mu sortableCallback, abych se vyhnul tomu, aby se název property ve schematu vyhledával. Pokud to ale vadí, že to není přímo ve schematu, pak jsem nenašel, jak to obejít. Jinak ale, jak říkám, jsem to vyřešil copy&pastnutím kódu z toho pull requestu, což není ideální, ale funguje to.
- Domki
- Člen | 310
Nyní jsem zkusil Repozitaře z YetOrmu rozšířit o IDataSource.
Ale trochu tápu jak implementovat nekteré funkce z rozhraní (sort,
limit).
Nevytvářel už někdo tento DataGrid s YetOrmem?
Domki napsal(a):
@PavelJanda Chtěl bych se zeptat jestli je nějaká možnost jak používat tento vypadajíc skvěle Datagrid s YetOrm
co přiřadit jako zdroj? zatím mi šlo jen YetormColekci převest na array
pak mi ale nefunguje například řazení
Nějaký elegantní řešení?
Díky
- Domki
- Člen | 310
@CZechBoY
Udelal jsem jednoduchou implementaci:
abstract class BaseRepository extends Repository implements IDataSource
{
/**
* @var EntityCollection $data
*/
protected $data;
/**
* Get count of data
* @return int
*/
public function getCount()
{
return $this->data ? $this->data->count() : $this->findAll()->count();
}
/**
* Get the data
* @return EntityCollection
*/
public function getData()
{
return $this->data ? $this->data : $this->findAll();
}
/**
* Filter data
*
* @param array $filters
*
* @return static
*/
public function filter(array $filters)
{
return $this->data = $this->findAll();
}
/**
* Filter data - get one row
* @param array $filter
* @return static
*/
public function filterOne(array $filter)
{
return $this->data = $this->findAll();
}
/**
* Apply limit and offset on data
* @param int $offset
* @param int $limit
* @return static
*/
public function limit($offset, $limit)
{
return $this->data->limit($limit, $offset);
}
/**
* Sort data
* @param Sorting $sorting
* @return static
*/
public function sort(Sorting $sorting)
{
$sort = $sorting->getSort();
if (count($sort) === 0) {
$array = [];
foreach ($sort as $column => $order) {
$array[$column] = $order == 'ASC' ? EntityCollection::ASC : EntityCollection::DESC;
}
$this->data = $this->data->orderBy($array);
}
return $this->data;
}
}
Ale v datagridu se nevypise zadny radek a je na nem napsano : ( Items:
1 – 0 from 4 )
Co mám špatně?
a při implmentaci daného rozhraní bude následně datagrid fungovat
plnohodnotně včetně všech možností?
- David Kregl
- Člen | 52
Pavel Janda napsal(a):
Přídána textarea u group actions, přidány volitelné class a jiné attributy u všech group acitons, viz http://ublaboo.org/…group-action#…
@pitr82, @DavidKregl
Super! Díky
- Domki
- Člen | 310
@CZechBoY no do $data jsem ukladal nalezené kolekce nad kterými pak
volam limit order..
A ta metoda ti vratí co? pole mi přijde nešikovné, a z EntityCollection na
nette/database to nepřevedu ne?
Nebo ty máš implementaci pro yetOrm? Neposlal bys mi jí?
Resp proč není už v defaultu v Datagridu?
Editoval Domki (24. 7. 2016 11:18)
- pitr82
- Člen | 121
pitr82 napsal(a):
@PavelJanda Mám na stránce více datagridu vytvořené jako komponenty pomocí factories. Jak mám při inline add invalidovat jen konkrétní grid?
Díky za nakopnutí.
@PavelJanda při inline ADD musím obnovit celou stránku.
$grid->reload
mi sice pošle jen grid, ale ten ještě nemá k dispozici nová data, dájí se data znovu načíst ? Aby přidávání projevilo pěkné ajaxově i s novou hodnotou?
- Pavel Janda
- Člen | 977
pitr82 napsal(a):
@PavelJanda Mám na stránce více datagridu vytvořené jako komponenty pomocí factories. Jak mám při inline add invalidovat jen konkrétní grid?
Díky za nakopnutí.
Stejně, jako každou jinou komponentu. Komponenta nese jméno, takže
například v presenteru budeš „invalidovat“ komponentu foo
takto: $this['foo']->redrawControl()
.
- Pavel Janda
- Člen | 977
@Domki @CZechBoY S čím by měl pracovat
YemORMDataSouce
? S YetORM\EntityCollection
? S dnbt?
Klidně to napíšu, akorát potřebuji kopnout.
- Pavel Kravčík
- Člen | 1195
@Domki, @PavelJanda: Mám takový dojem, že je to neřešitelné, že EntityCollection se již nedá filtrovat kvůli lazy přístupu. Řešilo se to u Grido.
My na všech nových projektech používáme
$repository->getTable()
nebo pole (tak 90% pro getTable()).
- Pavel Janda
- Člen | 977
@PavelKravčík @Domki Takže v podstatě jediná věc, kterou
mohu udělat je, že přidám do třídy Row
nějaký property
access pro YetORM\Entity
(to by se použilo, pokud by tedy někdo
na své straně implementoval svůj data source, který by stavěl na
jakýchkoliv kolekcích s YetORM entitami).
ArrayDataSource
počítá nyní s tím, že jednotlivé
položky pole jsou též pole. Tedy se nepoužívá třída Row
,
která by zpřístupňovala zmíněný property access u různých ORM entit.
To mohu změnit. ArrayDataSource
může používat Row
a tím pádem property access.
Jaký na to máte názor?
- Pavel Janda
- Člen | 977
@pitr82 Životní cyklus tvé instance datagridu je asi takovýto:
- Poslal jsi request na přidání položky
- Nette pozná, že požadavek míří na komponentu
- Zavolá se továrnička komponenty, vytvoří se instance komponenty
- Nastaví se datasource a všechny ostatní sloupce, filtry a podobně
- Továrnička vrátí komponentu
- Nette spustí všechny potřebné handlery v komponentě
- Tak, teď bohužel nestačí pouze překreslit komponentu (data source už je nastaven a jelikož se jedná o pole, nic se netahá „líně“ z databáze až na poslední chvíli). Takže si můžeš buď vytvořit nějaký lazy data source, nebo znovu přiřadit data source datagridu.
- Pavel Kravčík
- Člen | 1195
@PavelJanda: Mně to přijde zbytečná práce, aby fungovalo jen následující, což u nás považujeme za docela „prasárnu“ – nemá to prakticky žádný význam a pro větší tabulky je to pomalejší. Sice je to trochu znásilnění principu ORM, ale v tomhle případě je ORM nevhodné. :)
// Ošklivý přístup
$grid->setModel($repository->findAll()->toArray());
// Lepší přístup
$grid->setModel($repository->getTable());
//YetORM/Repository rozšíření
public function getTable($table = NULL)
{
return parent::getTable($table);
}
- Pavel Janda
- Člen | 977
@PavelKravčík Dobře, tak já nic dělat nebudu. :D
Souhlas, ta table
fungovat bude.
- Domki
- Člen | 310
@PavelKravčík
A vy používáte YetOrm s Datagridem jo?
Dík za nastin. Jen dotaz tím setModel je na mysli setDataSource, nebo to je nejaka vaše speciální funkce?
Kdyz jsem do datasource nastavil $repository->getTable(), tak datagrid
funguje super, aj s strankováním.
Jen mám dotaz, jak řešíte volaní funkcí z entit? V entitach mám funkce
například na ziskat Authora podle id, připadne získaní zaznamu pres
vazební tabulky.
Např:
$grid->allowRowsAction('delete', function ($item) {
return $item->getProductsWithBrand()->count() === 0;
});
mi vraci chybu ze funkce getProductsWithBrand není definovana.
Díky
Editoval Domki (27. 7. 2016 23:02)
- romiix.org
- Člen | 343
Napadlo mi zjednodušenie definície small inline edit, ale neviem či s tým nie sú nejaké problémy ktoré nevidím.
Pre small inline edit by bolo použiteľné aj:
$grid->addColumnText('name', 'Name')
->setEditable();
$grid->addInlineEdit()
->onControlAdd[] = function($container) {
$container->addText('id', '');
$container->addText('name', '');
$container->addText('inserted', '');
$container->addText('link', '');
};
$grid->getInlineEdit()->onSetDefaults[] = function($container, $item) {
$container->setDefaults([
'id' => $item->id,
'name' => $item->name,
'inserted' => $item->inserted->format('j. n. Y'),
'link' => $item->name,
]);
};
$grid->getInlineEdit()->onSubmit[] = function($id, $values) {
/**
* Save new values
*/
};
Pre formulár by sa použil automaticky form contajner nastavený pre daný
stĺpec z big inline edit a ak by nebol nastavený vlastný callback,
použil by sa $grid->getInlineEdit()->onSubmit[]
s nezmenenými dátami z $item
, iba s modifikovanou tou jednou
konkrétnou hodnotou, ktorá je menená.
Čo myslíte? Je to dobrý nápad?
- Pavel Janda
- Člen | 977
@Domki Asi je. Zkus to a uvidíš, není nic jednoduššího. :) Nebo máš na mysli konkrétní situaci?
Editoval Pavel Janda (28. 7. 2016 22:10)
- Šaman
- Člen | 2659
Ahoj, zkouším poprvé tento grid – čistá instalace composerem a
bowerem na web-projectu s Nette 2.3.
A když přejdu na stránku s gridem (bez parametru), naskočí mi poslední
stránka v gridu, kde jsem byl naposled. Nikoliv první stránka, jak bych
očekával. Při dalším stránkování se už stránka dostává i do adresy,
to je v pohodě. Toto chování je stejné při ajaxu i bez něj.
Je to feature, je to bug?
- Pavel Kravčík
- Člen | 1195
@Domki: Tam právě nevstupuje entita, ale ActiveRow (https://doc.nette.org/…ase/explorer). Takže takhle funkce je „nedostupná“. Případně by to šlo obejít možná nějak takto:
->setRender(function($row)
{
$entity = new Entity($row);
return $entity->customFunction();
})
Editoval Pavel Kravčík (29. 7. 2016 7:58)
- Pavel Janda
- Člen | 977
@Šaman Ano, datagrid si pamatuje sort, page, per page, hidden columns, filtry… Lze mu říci, aby si to nepamatoval.
Pokud taková funkcionalita nestačí, lze založit issue „aby si datagrid nepamatoval pouze page“ při pamatování věcí skrze session a nebo rovnou poslat stejnojmenný PR. :D
Nechám si projít hlavou plusy a mínusy obou variant.
- Šaman
- Člen | 2659
Pavel Janda napsal(a):
@Šaman Ano, datagrid si pamatuje sort, page, per page, hidden columns, filtry… Lze mu říci, aby si to nepamatoval.
Pokud taková funkcionalita nestačí, lze založit issue „aby si datagrid nepamatoval pouze page“ při pamatování věcí skrze session a nebo rovnou poslat stejnojmenný PR. :D
Nechám si projít hlavou plusy a mínusy obou variant.
Aha, a má ty parametry zobrazit v URL? Protože mě mate, že když přijdu
na stránku s Gridem, je už nějak nastavený, ale v URL to není zmíněno.
Takže by se mohlo i stát, že zkopíruji adresu a někomu ji pošlu, ale jemu
se zobrazí úplně jiná data. Nevím ale, jestli není chyba u mě (že to
napoprvé není v adrese).
Když pak ručně přejdu na nějakou stránku, tak se to do URL předá, to
už je v pohodě.
- Pavel Janda
- Člen | 977
@Šaman Ano, to je standardní chování. Datagrid si pamatuje
v session fitry, stránkování apod (dále jen filtry) a pokud přijdeš na
stránku s tímto datagridem, filtry se obnoví. Teprve potom se mohou na
stejné stránce propisovat do URl persistentní parametry (V případě, že
datagrid používá ajax, propisuje se state
presenteru do url
pomocí history API).
Jak bys to řešil? Budu rád za spásný nápad. :)
Pokud si má datagrid ukládat do session aktuální stav, nelze nijak
jednoduše změnit rovnou url při příchodu na stránku s datargidem, který
má již tyto informace v session. Musel by se předávat nějaký JS objekt
state
z PHP do JS a pak pokaždé kontrolovat, zda není náhodou
tento objekt „neprázdný“ a url prázdná..
Jiné řešení mě teď nenapadá a tohle se mi nelíbí.
- Danndy
- Člen | 35
@PavelJanda Ahoj, Naozaj super datagrid! Palec hore! Mal by som ale dve otázočky.
Keď som si skúšal tvoj datagrid a hral sa trocha s url, ktorá obsahovala nejaký sorting parameter (napr.: &doctrineGrid-sort[name]=DESC) a zmenil som „name“ na nieco ine (nesprávne) išlo to hneď do error 500. Je to niečo s čím by som si mal lámať hlavu?
Druhá otázka: Používam Doctrine 2 pre DataSource, a chcem v datagride zobraziť záznamy z tabulky „article“ ale aj spolu s kategóriou do ktorej su priaradene (ManyToOne). Je možne pre takýto stĺpec pridať FilterMultiSelect podla názvu kategórie? resp. Je možne v datasource použiť join a pracovať s join-utými entitami?
Ďakujem.
- Pavel Janda
- Člen | 977
@Danndy Díky.
- No pokud jsi změnil název sloupce, datagrid se bude snažit najít
neexistující sloupec, aby podle něj mohl setřídit data.. To je prostě
chyba. Mohl bych přidat nějaký „silent-mode“, pokud by byl zájem. Potom
by to prošlo. Sice nejsem úplně přesvědčen, že je to správná cesta, ale
budiž. Pokud se bojíš, že bude uživatel přepisovat url a nechceš mu ji
dát k dispozici, můžeš vypnout přepis url a nechat datagrid tiše pracovat
pouze se session (
$grid->setRefreshUrl(FALSE);
). DoctrineDataSource
normálně iteruje nad entitami, takže tam můžeš vypisovat jakkoliv složité vazby. A nebo si v šabloně volat sám metody entit. A nebo ještě několika způsoby. :D
- Danndy
- Člen | 35
@PavelJanda Díky za rýchlu odpoveď.
- Máť parametre filtrov/sortov v url je fajn vec. Viem, že si každý povie „kto by sa už len hrabal v url“ ale možno stojí za zváženie do budúcna, aby datagrid kontroloval či je stlpec pre sortovanie definovaný.
- Takto nejak to mám:
<?php
$grid->setDataSource($qb->select('a, c')->from('App\Entity\Article', 'a')->leftJoin('a.category' ,'c'));
...
$grid->addColumnText('category', 'Kategória', 'category.name')
->setSortable('c.name')
->setFilterMultiSelect($this->categoryFacade->getCategoryPairs())
->setCondition(function($fluent, $value) {
$fluent->where('c.id IN(:arr)')->setParameter('arr',implode(",", $value));
});
?>
Je aj to „prípustne riešenie“ ? alebo je niektore lepšie?
- Pavel Janda
- Člen | 977
@Danndy Můžeš na to založit issue? Úprava by neměla být velká.
A bez té custom condition ti filtrování nefunguje? Funkcionalita by měla
být nativně stejná..
(DoctrineDataSource::applyFilterMultiSelect()
). Asi bude potřeba,
abys definoval sloupec, který se má použít při vyhledávání. Takže by
mělo stačit něco takového:
$grid->addColumnText('category', 'Kategória', 'category.name')
->setSortable('c.name')
->setFilterMultiSelect($this->categoryFacade->getCategoryPairs(), 'c.id');
- Danndy
- Člen | 35
@PavelJanda
2. Dík moc krát, tvoj kód funguje :)
1. Áno, môžem vytvoriť. Ked som si prechádzal kód, dalo sa to oŠetrit jednou podmienkou vo funkcii DataGrid->createSorting(…); Hneď ma ale napadla jedna otázka, podporuje DataGrid aj sorting podľa viacerých stĺpcov naraz?
Editoval Danndy (4. 8. 2016 16:06)
- ramaskrik
- Člen | 3
Zdravím,
s Nette ešte len začínam, takže možno to bude taká noob otázka.
Stiahol som si ublaboo cez composer a hodil podľa oficiálneho tutoriálu
kód do presenteru.
Ako mám teraz vložiť datagrid do šablóny? render() to asi nebude, čo?
public function renderDefault()
{
$this->createComponentGrid('authorizations')->render();
}
public function createComponentGrid($name)
{
$grid = new DataGrid($this, $name);
$grid->setDataSource($this->database->table($name)->order('id DESC'));
$grid->addColumnText('phone', 'telefón');
$grid->addColumnText('code', 'kód');
}
Editoval ramaskrik (4. 8. 2016 17:08)
- romiix.org
- Člen | 343
Do šablóny sa vloží komponenta sama – použi ju rovno v šablóne.
{control grid}
ramaskrik napsal(a):
- romiix.org
- Člen | 343
Use case
V detaile položky zobrazujem formuláre s nastaveniami položky. Veľmi rozsiahle, podelené v taboch. Je to výborne použiteľné, pretože je takto možné ovládať takmer celú aplikáciu z jedného gridu.
Problém
Takto načítané formulárové komponenty nepracujú korektne, pretože ide o formulár vo formulári.
Komponenta <form> filter
obaľuje celý grid od začiatku
po koniec.
Riešenie
Rozdeliť formulár na:
- filter
- groupAction
- add
- edit
- perPage
Chcekboxy pre hromadné akcie by boli riešiteľné pripojením k formuláru
atribútom form
. Žiaľ, vyžadovalo by to JS fix pre IE/Edge.
Záver
Čo na to vravíte? Hlavne @PavelJanda