ublaboo/datagrid: mocný, rychlý, rozšiřitelný, hezký, anglicky dokumentovaný datagrid
- chladekt
- Člen | 10
@PavelJanda Opožděně reaguji k problému ke 2 gridům na 1 stránce. Iframe mi přijde jako komplikované řešení. Na jedné stránce jsem to pořešil tak, že jsem pro ty gridy vypnul ajax, takže se refreshuje celá stránka. Na druhé stránce mi to nedělá – nejspíš proto, že ty tabulky mají různé sloupce.
- Pavel Janda
- Člen | 977
@pp Asi bych si připravil vlastní podmínku… https://contributte.org/…filters.html#…
- pavel_4
- Člen | 13
Ahoj, dá se někde v komponentě (nebo v šabloně) dostat k vyfiltrovaným položkám?
Vysvětlím – mám vlastní hromadné operace, které fungují dobře, mám tlačítko vybrat vše na stránce, které je taky ok, ale potřebuju udělat checkbox „vybrat vše vyfiltrované“. Chtěl jsem po kliku na tento checkbox získat pole všech hodnot primárního klíče všech vyfiltrovaných záznamů (ID), ale to se mi nedaří.
Když se podívám do data source, kde je QueryBuilder, tak obsahuje všechny položky (bez filtru). Jde to řešit? Zkoumal to už někdo?
- chladekt
- Člen | 10
@PavelJanda Když teda chci mít 2 gridy se stejnými sloupci na jedné stránce a jejich konfliktům chci zabránit vypnutím AJAXu (může být vypnutý na celé stránce, ale na jiných stránkách ho mám zapnutý), tak nejjednodušší způsob je odstranit ze vsech trid v těch gridech ajax? Zkoušel jsem také nevkládat nette.ajax.js, ale pak mi jiné js soubory házely chyby (třeba datagrid.js).
- milos
- Člen | 1
Ahoj,
lze nějak nastavit Datagrid tak, aby u něj byla editovatelná pole rovnou
editovatelná? Tzn. bez nutnosti kliku do daného pole, případně kliku na
tlačítko (akce), které přemění pole na editovatelné?
Příklad:
Mám sloupec „Počet ks“, který je editovatelný. Současné řešení je
takové, že uživatel musí nejprve kliknout na pole a teprve pak může
upravit hodnotu. Mně by se hodilo, kdyby pole bylo editovatelné rovnou –
„ve stavu Uprav hodnotu“ – bez nutnosti kliku.
Předem mockrát díky za jakoukoli radu!
- magenzajin
- Člen | 9
Ahoj vše!
Chci v rámci jednoho gridu vzít z jiné tabulky client sloupec email. Vidím
to na NetteDatabaseTableDataSource.
Takže do gridu toto:
$grid->addColumnText(‚email‘, ‚Email‘, ‚:client‘);
Jak by ale měla vypadat funkční implementace..?? v rámci třídy
i v rámci metody
public function createComponentGrid($name) ???
Omluvte začátečníkovu neznalost.
Díky!
Editoval magenzajin (17. 6. 2019 15:19)
- Pavel Janda
- Člen | 977
@magenzajin
Třaba takto:
namespace MujNapespace;
use Nette\Database\Context;
class NejakyPresenter
{
/**
* @var Context
* @inject
*/
public $context;
public function createComponentGrid(): DataGrid
{
$grid = new DataGrid;
$grid->setDataSource($this->context->table('client'));
$grid->addColumnText('email', 'Email', 'client');
return $grid;
}
}
A nebo se inspiruj dalšími příklady zde: https://github.com/…tte-datagrid
Všechny příklady jsou reálně – běží jako demo zde: https://examples.planette.io/…te/datagrid/
Editoval Pavel Janda (17. 6. 2019 16:46)
- magenzajin
- Člen | 9
Dík. To vypadá gut,ale co s tímhle pak: There is already action at key [email] defined… Dík
- Pavel Janda
- Člen | 977
@magenzajin Nejspíš definuješ dvě akce na satejném klíči. Budeš tam mít něco jako
$grid->addAction('email', ....);
$grid->addAction('email', ....);
- magenzajin
- Člen | 9
Takhle vypadá kód před refractoringem. Taskem je přidat email z tabulky client. Přičemž datasource je nyní PricelistHistoryRepository. Je to dosti rozmrvený kód. Přičemž by to mělo být cajk. Máme jeden table pricelists_history a table client. V té první máme user_id a v té druhé email..
$grid = $this->create($name);
//$grid->setDataRepository($this->repository->getPricelists()->fetchAll());
$clientId = $this->presenter->getParameter('id');
if ($clientId) {
// $client = $this->clientRepository->getById($clientId);
$grid->setFilter(['user_id' => $clientId ?: "error"]);
}
$grid->addColumnNumber('user_id', 'User ID')
->setFilterText()
->setExactSearch();
//->setTemplate(__DIR__ . '/username.latte');
/*$grid->unsetFilter('user_id')
->getColumn('user_id')
->setFilterText('user_id.email');*/
$grid->addColumnDateTime('time');
$grid->addColumnText('file_name', 'URL');
$grid->addColumnText('export_type', 'Typ');
$grid->addActionCallback('download', 'Stáhnout', function ($id) {
try {
$file = $this->repository->getById($id)->file_name;
$file = explode('/', $file);
$file = array_pop($file);
$this->getPresenter()->terminate((new FileResponse(WWW_DIR . '/data/pricelists/' . $file, $file))
->send($this->getPresenter()->getHttpRequest(), $this->getPresenter()->getHttpResponse()));
} catch (BadRequestException $e) {
$this->getPresenter()->flashMessage($e->getMessage());
}
});
- Pavel Janda
- Člen | 977
@magenzajin Nezdá se mi, že by tato factory vyhazovala
There is already action at key [email] defined
… nemáš tam
žádnou akci na klíči email
.
- magenzajin
- Člen | 9
To je původní třída. Když do ní zkusím dle tvého příspěvku
s datasource <?php
$grid->setDataSource($this->context->table(‚client‘));
$grid->addColumnText(‚email‘, ‚Email‘, ‚client‘); ?>, tak se
pak ohlásí There is already action at key [email] defined..
takhle tam vypadají ještě uses:
<?php
namespace ***\Components;
use app\components\Grids\BaseGridControl;
use Nette\Application\BadRequestException;
use Nette\Application\Responses\FileResponse;
use *****\Permission;
use *****\PricelistsHistoryRepository;
class PricelistGridControl extends BaseGridControl
{
...
?>
- Pavel Janda
- Člen | 977
@magenzajin Zdá se mi, že další diskuze už nepatří do tohoto vlákna..
Zkus postupovat fakt postupně a co nejjednodušeji. Udělej si prázdnou factory, kam dáš to, co jsem poslal. Můj kód jistě danou výjimku nevyhodí. A pak postupně přidávej řádek po řádku další funkcionalitu. Myslím, že tak najdeš problém, který ti výjimku způsobuje.
Píšeš, že dědíš od nějakého BaseGridControl
→
nedefinuje se ti třeba tam už nějaká akce nebo nějaký sloupec?
Atd.
- magenzajin
- Člen | 9
Už na tom dělám. Celá ta implementace gridu u nás je nějak mimo .. Každopádně díky. :)
- jikki
- Člen | 73
Ahoj lidi,
jak byste udělali tabulku, která bude mít možnost přepnout zobrazení
položek jednotlivě (zobrazí se každý položka databáze) nebo seskupeně
(položky se stejnými vlastnosti a jejích počet)?
Zatím jsem to vyrešil následovně:
Přidal jsem dvě tlačítka do toolbaru, ‚zobrazit jednotlivě‘ a
‚zobrazit seskupeně‘. Handly těch dvou tlačítek mění ajaxovým
požadavkem hodnotu v session podle toho zda chci zobrazit jednotlivě nebo
seskupeně a udělá reload tabulky. Podle hodnoty v session také nastavuji
v metodě createComponentMyGrid dataSource a zobrazuji sloupce. Pro pohled
seskupeně přidávám do dotazu Count(*) a GroupBy a vynechávám některé
sloupce, které mají jedinečné hodnoty.
Tohle řešení funguje, ale jen do dody než použiju filtry. Pokud začnu používat filtry, tak přepnutí nefunguje na první kliknutí, ale až na druhé. Nedaří se mi to vyřešit, aby to fungovalo i s při použití filtrů, tak jak se očekává. Jedinné řešení je používat redirect(‚this‘) místo ajaxu + reloadu tabulky. Nicméně rád bych to zprovoznil s ajaxem.
Poradí někdo lepší způsob? Případně pokud bych udělat sandbox na githubu?
Díky za rady
- Pavel Janda
- Člen | 977
@zool Třída Ublaboo\DataGrid\DataModel
(neřešil bych
její jméno, historické důvody…) má eventy ::$onBeforeFilter
,
::$onAfterFilter
a ::$onAfterPaginated
. Ty by mohly
fungovat pro tvůj účel skvěle. Akorát se bohužel nedostaneš k instanci
toho dataModelu. Nicméně pokud bys do masteru poslal pull-request
s přidáním metody ::getDataModel(): DataModel
do třídy
DataGrid
, tak ho rád mergnu. 👍
- Petr Parolek
- Člen | 455
Pavel Janda napsal(a):
@IJVo Nezmizela. :) Jen se přejmenovala kvůli PHP 7.2 a dědičnosti. A když už jsem dělal BC break, udělal jsem ho pořádně:
$grid->setConfirm('Do you really want to delete item %d?', 'id');
->
$grid->setConfirmation(new StringConfirmation('Do you really want to delete item %d?', 'id'));
A pro callback confirmation je tam
CallbackConfirmation
.Jakmile vydám verzi 6, pustím sem celé release notes. Už je to za dveřmi!!
Ahoj, chybí v dokumentaci – stále je tam
->setConfirm('Do you really want to delete row %s?', 'name'); // Second parameter is optional
https://github.com/…s/actions.md#…,
mám poslat PR?
- dTTb
- Člen | 30
Nevim jestli me nepostihl zachvat slepoty, ale nemuzu ve full dokumentaci najit filtry (krom odstavce v kapitole Localization). Na puvodnich strankach je jim venovana cela kapitola. Nebo je ublaboo.org hlavni zdroj dokumentace?
- Pavel Janda
- Člen | 977
@dTTb Jojo, ta stránka tam chybí, víme o tom, podíváme se na to.
Jako hlavní zdroj dokumentace by měly sloužit README na GitHubu (https://github.com/…master/.docs), které se generují do čitelnější formy na stránkách Contributte. 👍
- magenzajin
- Člen | 9
Ahoj,
už jsem tu něco podobného řešil. Jak řešíte ( co nejelegantněji :) )
více datasourců v jednom gridu? Díkes
- dTTb
- Člen | 30
@Felix diky
Jeste drobny dotaz ke Column Link. Da se nejak jednoduse zmenit text odkazu ktery to generuje? Pridat callback, parsovat vygenerovanej odkaz a zase odkaz lepit mi neprislo jako dobrej napad. Nakonec jsem si podedil DataGrid a ColumnLink, ale ani to mi neprijde idealni.
- RePRO
- Člen | 32
Ahoj. Mám problém s řazením a poté filtrem.
Mám dvě pole datum a osoba, jenže když si pole datum seřadím vzestupně a dám poté filtr osoby, tak se mi data seřadí do výchozího stavu (default sort). Avšak zobáček řazení zůstane OK :D Potřebuji nechat datum jak bylo. Je možné tohle nějak pořešit?
- Failips
- Člen | 54
Ahoj,
po upgrade na Ublaboo/Datagrid v6.2.0 som narazil na chybičku:
Call to undefined method Ublaboo\DataGrid\Column\Action::setConfirm()
kód je nasledovný:
$grid->addAction('delete', '', 'deleteKeyword!')
->setIcon('trash')
->setTitle('Smazat')
->setClass('btn btn-xs btn-danger ajax')
->setConfirm('Vážně si přejete odstranit klíčové slovo %s?','nazov');
Čím bola nahradená funkcia setConfirm() a aké je jej správne použitie?
Vďaka, Filip.
- Failips
- Člen | 54
radas napsal(a):
@Failips https://github.com/…s/tag/v6.0.0
Ďakujem. Presne preto sa pýtam na správne použitie (nejakú ukážku), nakoľko nemám ani potuchy čo za triedy sú StringConfirmation a CallbackConfirmation a ako sa s nimi pracuje pokiaľ chcem dosiahnuť rovnakých výsledkov ako v predchádzajúcich verziách.
- Failips
- Člen | 54
Ok. Tu je riešenie pre tých, ktorí by mali podobný problém :D Použitie tejto funkcie je fakt nádherné :D
$grid->addAction('delete', '', 'deleteKategoria!')
->setIcon('trash')
->setTitle('Smazat')
->setClass('btn btn-xs btn-danger ajax')
->setConfirmation(new \Ublaboo\DataGrid\Column\Action\Confirmation\StringConfirmation('Vážně si přejete odstranit kategorii %s?','nazov'));
Editoval Failips (16. 7. 2019 11:50)
- Pavel Janda
- Člen | 977
@Failips Nádherné myslíš ironicky? :) Udělal jsem to tak se kvůli zachování typovosti. Chápu, že se to může zdád na první pohled nepřehledné, mně to ale připadá ve výsledku přehlednější. :P
- Failips
- Člen | 54
Narazil som na ďalší problém, s ktorým si dosť lámem hlavu. Rád by som použil funkciu setItemsDetail podobne ako je to ukázané v ukážkach .
Kód Presenter:
$grid->setItemsDetail(APP_DIR . '/MainModule/templates/Porada/grid_item_detail.latte');
$grid->setItemsDetailForm(function(\Nette\Forms\Container $container) use ($grid, $presenter) {
$container->addHidden('id');
$container->addText('nazov');
$container->addSubmit('save', 'Save')
->onClick[] = function($button) use ($grid, $presenter) {
$values = $button->getParent()->getValues();
$presenter['examplesGrid']->redrawItem($values->id);
};
});
Kód Latte:
{extends $originalTemplate}
{block detail}
<h2>{$item->getNazov()}</h2>
<p>Lorem ipsum ...</p>
{formContainer items_detail_form-{$item->getId()} }
{input id, value => $item->getId()}
{input nazov, value => $item->getNazov()}
{input save}
{/formContainer}
{/block}
Chyba vyvolaná riadkom „{formContainer items_detail_form-{$item->getId()} }“:
Nette\InvalidArgumentException
Component with name '1019' does not exist.
Ak daný riadok upravíme na {formContainer items_detail_form} }, tak sa cez chybu dostaneme ale dostaneme ďalšiu vyvolanú riadkom „{input id, value ⇒ $item->getId()}“:
Nette\MemberAccessException
Call to undefined method Nette\Forms\Container::getControl(), did you mean getControls()
A pokiaľ v tomto stave máme v detaile (vo vnútri formContainer
items_detail_form) ďalší formContainer (napr. inner_form), tak
$container v presentéri nebude odkazovať na
items_detail_form ale na tento ďalší formContainer, čiže
ak budeme chcieť vložiť do detailu niečo napr. pomocou funkcie addHidden(),
tak sa tento prvok vloží do toho inner_form a
nie do items_detail_form.
Je chyba v Ublaboo/Datagrid alebo je to spôsobené mojou zlou implementáciou ItemsDetail? Ak je chyba na mojej strane ako sa má správne implementovať ItemsDetail vo Ublaboo/Datagrid v6.2.0?
Ďakujem, Filip.
- Pavel Janda
- Člen | 977
Demo (viz zde) funguje z repozitáře v playgroundu – https://github.com/…tte-datagrid. Zkus to u sebe rozjet a porovnat se svým kódem. :)
- Failips
- Člen | 54
Díky za tip, rozbehol som to u seba. Aby som si bol istý, že je CSS a JS rovnaké tak som do playground verzie vložil môj bower.json avšak, nechápem prečo, inlineAdd v playground ide a u mňa s rovankým kódom nejde :D Nejaké tipy, čo by som ešte mohol skontrolovať?? :D
Edit: všimol som si, že riadok pre inlineAdd sa pridá avšak je skrytý.
Editoval Failips (23. 7. 2019 12:37)
- magenzajin
- Člen | 9
Ahoj,
jako modalEdit, který mi dá formulář editace např.klienta se vším, co
chci editovat.. rád bych duplikoval klienta, se stejným formulářem, ale
abych neupdatoval, ale nově insertoval… Je nějaká spešl feature datagridu
pro toto??
Dík
- R@da
- Člen | 28
Ahoj,
už se to tu řešilo, ale bohužel jsem nikde nenašel odpověď. Řeším, jak
při inline editaci zobrazit datepicker?
Respektive, zobrazit se mi ho podařilo, ale když zvolím datum, tak se textbox
zruší a nic se neuloží.
Mám to nyní takto:
$grid->addColumnDateTime('customer_invoice_paid', 'Zaplaceno')
->setEditableCallback(function($id, $value) {
echo("Id: $id, new value: $value"); die;
})
->setEditableInputType('text', ['class' => 'datepicker', 'onClick' => '$(this).datepicker("show");']);
Do budoucna by bylo možná dobré automaticky nabízet kalendář, když se
jedná o „ColumnDateTime“. To jenom takový nápad na vylepšení.
Má někdo stejný problém? Jak to prosím vyřešit?
Předem moc děkuju.
- Failips
- Člen | 54
Failips napsal(a):
Díky za tip, rozbehol som to u seba. Aby som si bol istý, že je CSS a JS rovnaké tak som do playground verzie vložil môj bower.json avšak, nechápem prečo, inlineAdd v playground ide a u mňa s rovankým kódom nejde :D Nejaké tipy, čo by som ešte mohol skontrolovať?? :D
Edit: všimol som si, že riadok pre inlineAdd sa pridá avšak je skrytý.
Po hlbšom skúmaní kódu som zistil, že pri kliku na tlačítko „+“, ktoré má zobraziť riadok s inlineAdd, sa nezavolá event, ktorý má za úlohu odstrániť z vytvoreného riadku inlineAdd triedu datagrid-row-inline-add-hidden (datagrid.js):
$(document).on('click', '[data-datagrid-toggle-inline-add]', function(e) {
var row;
e.stopPropagation();
e.preventDefault();
row = $(this).closest('.datagrid').find('.datagrid-row-inline-add');
if (row.hasClass('datagrid-row-inline-add-hidden')) {
row.removeClass('datagrid-row-inline-add-hidden');
}
return row.find('input:not([readonly]),textarea:not([readonly])').first().focus();
});
Považujete toto za správne chovanie a je daná trieda odstraňovaná iným spôsobom (ktorý u mňa nefunguje)?
- R@da
- Člen | 28
zoool napsal(a):
Ahoj narazil jsem na problém v Datagridu ^6.2, setConfirm u akce se přejmenovalo na setConfirmation s použitím správného Confirmation? V dokumentaci je to pořád stejné.
Děkuji
Ahoj,
já to vyřešil takto:
use Ublaboo\DataGrid\Column\Action\Confirmation\StringConfirmation;
$grid->addAction('storno', '', 'storno!')
->setIcon('times')
->setTitle('Storno')
->setClass('btn btn-xs btn-danger ajax')
->setConfirmation(new StringConfirmation("Opravdu chcete stornovat?"));
- Pavel Janda
- Člen | 977
@zoool Ahoj, opravil jsem dokumentaci: https://contributte.org/…actions.html#api
Jinak pro všechny: kdyby někdy někdo narazil na bug v dokumentaci, lze poslat opravný PR: https://github.com/…master/.docs :) :) 👍👻
- Pavel Janda
- Člen | 977
Failips napsal(a):
Existuje spôsob, ktorým by sa pri vykreslení inlineEditu dal zachytiť event v jQuery/JS?
Určitě ano. V JS datagridu je následující kód:
$.nette.ext('datagrid.inline-editing', {
success: function(payload) {
if (payload._datagrid_inline_editing) {
// Něco...
}
}
});
Klidně si můžeš zaregistrovat vlastní nette.ajax.js extension, kde bude místo „// Něco…“ tvůj kód.
- nocturne32
- Člen | 21
Ahoj, jak je to s dokumentací datagridu na ublaboo? Pouze to přesměrovává na contributte, ale tam toho moc není, co se informací týče.
Edit: ah, pardon, akorát teď jsem si všiml, že v repu jsou alespoň ty docs více rozepsaný, ale škoda té stránky, byla moc fajn :-)
Editoval nocturne32 (30. 7. 2019 12:13)
- cafesk8
- Člen | 103
Zdravím,
mám export do CSV
$grid->addExportCsv('Export', 'users'.time().'.csv')
->setTitle('Export uživatelů')
->setColumns([
$column_email,
...
...
]);
ale klient požaduje aby export byl v XLS, protože pracují s MS Excel a v něm se prý po otevření CSV a opětovném uložení se z něj stane sypaný čaj a všechna data na řádku již nejsou ve sloupcích, ale za sebou na řádku. Dále má problém s diakritikou, která se mu nezobrazí správně (mně ano, stejně tak v Libre Office, tak v Google Sheets).
Máte nějaký nápad jak udělat export do XLS? Nedá se třeba soubor
místo stažení prohlížečem pouze někde uložit a pak si ho převést
pomocí phpoffice/phpspreadsheet
?
Děkuji
- Felix
- Nette Core | 1197
nocturne32 napsal(a):
Ahoj, jak je to s dokumentací datagridu na ublaboo? Pouze to přesměrovává na contributte, ale tam toho moc není, co se informací týče.
Edit: ah, pardon, akorát teď jsem si všiml, že v repu jsou alespoň ty docs více rozepsaný, ale škoda té stránky, byla moc fajn :-)
Ta stranka se premistila na jiny web, jinak obsah zustal stejny nebo lepsi. :-)