ublaboo/datagrid: mocný, rychlý, rozšiřitelný, hezký, anglicky dokumentovaný datagrid
- suwer
- Člen | 33
@PavelJanda @Šaman @galab
Pro multi-column sort
to samozrejme dava vetsi smysl. Ale
i pristup bez resetu dava smysl, viz. demos.devexpress.com (proste se resetuje prechodem zpet na
single-column sort
). Chapu, ze zvyk Ublaboo uzivatelu v tom pak
hraje zasadni roli. Ja se to nesnazim napadnout, jenom mam jiny pohled na vec,
to je cele :-).
@galab
Jenze v tom prikladu se tak chova pouze pro multi-column sort
, ale
single-column sort
umoznuje ASC, DESC
porad dokola.
Zkus si to datatables.net
@Šaman
Ty priklady byly ilustrativni a je prece jedno, co pak pouzijes za datasource.
Vsechno to nakonec na frontendu pouziva JS (Ublaboo, DataTables, ASP.NET
GridView, …).
- Šaman
- Člen | 2659
@suwer: Původně jsem chtěl napsat právě že Ublaboo a Grido to
v principu umí i bez JS a ten je jen pro uživatelský komfort.
A že ty JS tabulkovače jsou spíš odlehčené ke zlepšení zobrazení již
existující tabulky, protože většinou neslouží k filtrování velkého
množství dat (u těch čistě JS by musela zdrojová HTML tabulka obsahovat
všechny záznamy, což u rozsáhlých dat většinou nechceš), zatímco plné
backendové gridy se naopak snaží mít UI i pro rozsáhle filtrování a
složitéjší řazení. Obecně to je sice podobné zadání, ale řeší to
jinou potřebu. Ale máš pravdu, že obecně to není důležité.
Co je důležité, že všechny tvoje příklady neumí řazení podle více sloupců.
Editoval Šaman (26. 9. 2019 18:40)
- suwer
- Člen | 33
Šaman napsal(a):
Co je důležité, že všechny tvoje příklady neumí řazení podle více sloupců.
Na ten, co upozornil @galab (datatables.net), umi multi-column sort
, staci
pri razeni podrzet Shift. Pro multi-column sort
se chova stejne,
jako Ublaboo, ale single-column sort
umoznuje
ASC, DESC
porad dokola.
A muj priklad ASP.NET DataGridu (demos.devexpress.com) taky podporuje
multi-column sort
s jinym pristupem (resetuje prechodem zpet na
single-column sort
).
Nebo jsem te spatne pochopil :-)
Editoval suwer (28. 9. 2019 9:08)
- pp
- Člen | 50
Ahoj, poprosil bych o nasmerovani.
Pouzivam nize uvedeny zapis a mam problem, ze pokud vyberu polozku ze seznamu,
neaplikuje se filtrace.
Staci ale zmenit pocet zobrazenych zaznamu v paginatoru a pak uz to beha
OK.
Kde by mohl byt problem ?
$grid->addColumnText('device_id', 'device')->setAlign('center')->setSortable()
->setReplacement($this->deviceManager->getDevice())
->setFilterSelect($this->deviceManager->getDevice())
->setAttribute('class', "selectpicker")
->setAttribute('data-live-search', "true")
->setAttribute('title', "Vyberte zařízení z nabídky ...");
Editoval pp (1. 10. 2019 12:30)
- jikki
- Člen | 73
Ahoj,
když si dám do setFilterSelect nebo groupAction pole, kde hodnoty obsahují
tečky, tak vyneredorávní selectu není správně. Chybí tečky nebo čast
hodnoty. Dělám něco špatně?
<?php
$arr = ['.a', 'a.', 'a.b', 'a.b.c'];
$grid->addColumnText('test', Test)->setFilterSelect($arr);
$grid->addGroupAction('Test', $arr)->onSelect[] = function (array $ids, $selected) {};
?>
Vyrendorování vypadá takto. Dá se říct, že ořízne to, co je před první tečkou, pokud tam něco je, včetně tečky.
<option value="0">a</option>
<option value="1"></option>
<option value="2">b</option>
<option value="3">b.c</option>
Mám poslední verzi datagridu, u předchozích jsem si nevšiml.
díky moc
- jikki
- Člen | 73
ali napsal(a):
@jikki Typuju ze to bude delat translator, zkus ho vypnout.
Nebo vkladej hodnoty pres NotTranslate wrapper.
@ali máš pravdu, dělá to translator. Vypnutí či not translate wrapper pomáhá. Translator ale potřebuji mít zapnutý, tak škoda, že není u GroupAction možnost setTranslateOption jako je u Filtru. Nedaří se mi ten wrapper aplikovat na pole.
Díky za pomoc
Editoval jikki (15. 10. 2019 9:07)
- Petr Daňa
- Člen | 109
Ahoj, díky za super komponentu, aktualizuju jednu historickou aplikaci na Nette 2.4 (časem na 3.0, ale to až později), takže jsem hledal náhradu za Grido :) Potřeboval bych poradit s jednou specialitou, jestli to vůbec nějak půjde, klidně i za cenu hacku přímo v kódu Datagridu (v Gridu jsem to taky tak nakonec musel udělat). A sice mít možnost nastavit, že se vůbec nebudou načítat data, pokud je filtr prázdný. Zkoumal jsem zdrojový kód (verze 5.7.1 pro Nette 2.4), ale ikdybych vytvořil potomka DibiFluentDataSource, abych upravil getData(), tak tam nemám jak zjistit, jestli ten filtr je prázdný nebo ne. Takže jediné, co bych asi aktuálně mohl udělat je upravit přímo DataModel a ve filterData() si přidat podmínku pro volání datasource->getData(). Nebo existuje jiný (a správnější) způsob, jak toho docílit? Díky za pomoc.
EDIT: respektive asi dát rovnou podmínku na začátek filterData() a pokud je filtr prázdný, tak vrátit rovnou prázdné pole.
EDIT2: hm, tak to nefunguje, jsem v koncích :(
Editoval Petr Daňa (20. 10. 2019 22:22)
- Pavel Janda
- Člen | 977
@PetrDaňa Ahoj. Možná zkus v presenteru před vyrenderováním
datagridu prostě jen zkontrolovat hodnotu persistentní proměnné
DataGrid::$filter
– když bude prázdná, vyrenderovat jinou
šablonu. Jen to jen nápad, nezkoušel jsem to. Ještě se nad tím
zamyslím. :)
- Petr Daňa
- Člen | 109
@PavelJanda no, zkoušel jsem to vymyslet, ale nepovedlo se, už dlouho jsem v Nette nedělal :-/ Já ten Datagrid renderuju až v šabloně přes {control grid}, takže v presenteru v renderXxx() metodě vlastně ještě není vůbec dostupný.
No, nakonec jsem udělal ten hooodně nepěkný hack knihovny, na který nejsem vůbec pyšný, ale potřebuju se už pohnout dál, tak než přijdu na něco jiného nebo budu mít čas to hacknout „hezčeji“ (což se obávám hned tak nebude). Do DataModel jsem přidal public $noFetchingWhenEmptyFilter, v metodě filterData() pak mezi zpracováním filtrů a blokem volání getData() jsem dal tohle:
if ($this->noFetchingWhenEmptyFilter) {
$emptyFilter = true;
foreach ($filters as $filter) {
if ($filter->isValueSet()) {
$emptyFilter = false;
break;
}
}
if ($emptyFilter) {
return array();
}
}
a v DataGridu jsem dal jako public $dataModel, abych se přes něj v mém presenteru dostal na ten příznak. No, snad bude čas to vymyslet jinak, ale bez úpravy kódu v knihovně to s největší pravděpodobností nepůjde.
EDIT:
Tak jsem to alespoň mírně upravil, v DataGrid jsem vrátil zpět ten field
na protected a udělal public setter
public function setNoFetchingWhenEmptyFilter($enable = true) {
$this->dataModel->noFetchingWhenEmptyFilter = $enable;
}
Editoval Petr Daňa (24. 10. 2019 21:19)
- n3t
- Člen | 37
Ahoj, existuje někde funkční příklad s setItemsDetailForm? Zkoušel jsem vše možné, ale nejsem schopen to rozběhnout. Nefunguje mi ani příklad z dokumentace:
public function createComponentGrid($name)
{
$grid = new DataGrid($this, $name);
$grid->setDataSource($this->database->table('test')->order('id DESC'));
$grid->setTemplateFile(__DIR__ . '/../templates/Test/grid.latte');
$grid->addColumnText('name', 'company.grid.name');
$presenter = $this;
$grid->setItemsDetail();
$grid->setItemsDetailForm(function(Nette\Forms\Container $container) use ($grid, $presenter) {
$container->addHidden('id');
$container->addText('name');
$container->addSubmit('save', 'Save')
->onClick[] = function($button) use ($grid, $presenter) {
$values = $button->getParent()->getValues();
$presenter['grid']->redrawItem($values->id);
};
});
return $grid;
}
a grid.latte
{extends $originalTemplate}
{block detail}
<h2>{$item->name}</h2>
<p>Lorem ipsum ...</p>
{formContainer items_detail_form}
{input id, value => $item->id}
{input name, value => $item->name}
{input save}
{/formContainer}
Končí chybou
Nette\MemberAccessException
Call to undefined method Nette\Forms\Container::getControl(), did you mean getControls()?
Pokud vynechám z šablony formContainer, detail funguje, já bych ale v detailu rád editační formulář.
V dokumentaci je navíc použito
{formContainer items_detail_form-$item->id}
, to mi ale zas
končí chybou Component with name '2' does not exist.
Používám Nette 3.0, DataGrid 6.2.3. S Nette začínám, tak prosím pomalu na mně :) Dík za nasměrování.
- jval
- Člen | 36
@n3t nakonec jsem to vyřešil tak, že tlačítko pro smazání posílám na handleConfirm a v modalu tlačítko teprve na handleDelete. Děkuji
Ale mám ještě jeden dotaz. Mám v gridu sloupec s počtem dětí ke každé škole.
$grid->addColumnNumber('childs', 'Dětí')->setRenderer(function ($item) {
return $item->related('user', 'company_id')->count();
})->setAlign('center');
a pokud chci použít na tento sloupec summary.
$grid->setColumnsSummary(['childs']);
laděnka hlásí Cannot read an undeclared column ‚childs‘.
Editoval jval (2. 11. 2019 12:14)
- strunc
- Člen | 7
Ahoj, trápím se už několik hodin možná triviální záležitostí
v Ublaboo datagridu. Potřebuji v pravidelných časových intervalech
načíst Ajaxem aktuální data z DB. Resp. mi jde hlavně o jeden sloupec aby
se jeho data měnila podle aktuálního stavu v DB. Jako zdroj dat pro datagrid
používám dataSource.
Zkusil jsem si pridal do sablony s datagridem takovy JavaScript, sice Ajaxové
požadavky běží bez chyby, ale datagrid na změny v DB nereaguje.
setInterval(function () {
if ($('.datagrid').length) {
return $.nette.ajax({
type: 'GET',
url: $('.datagrid').first().data('refresh-state')
});
}
}, 1000);
Používám verzi 5.7.0, Nette 2.4.
Prosím o nasměrování, už fakt nevím jak na to.
Děkuji.
- n3t
- Člen | 37
K výše popsanému problému s setItemsDetailForm – jedná se o chybu
v dokumentaci.
Následující změna v šabloně funguje:
{extends $originalTemplate}
{block detail}
<h2>{$item->name}</h2>
<p>Lorem ipsum ...</p>
{formContainer items_detail_form}
{formContainer items_detail_form_$item->id}
{input id, value => $item->id}
{input name, value => $item->name}
{input save}
{/formContainer}
{/formContainer}
Editoval n3t (5. 11. 2019 2:25)
- n3t
- Člen | 37
Tak jsem ještě narazil na jednu skrytou zradu s ItemsDetailForm, pokud se používá nějaká validace, je potřeba Submit buttonu nastavit Scope, jinak se validuje i vše ostatní (např. u mně to byl InlineAdd):
$grid->setItemsDetailForm(function(Nette\Forms\Container $container) use ($grid, $presenter) {
$container->addHidden('id');
$container->addText('name');
$container->addSubmit('save', 'Save')
->setValidationScope([$container])
->onClick[] = function($button) use ($grid, $presenter) {
$values = $button->getParent()->getValues();
$presenter['grid']->redrawItem($values->id);
};
});
Mám to taky doplnit do dokumentace (je to možná trochu specialita…)?
- n3t
- Člen | 37
Tak ještě na jednu věc jsem narazil. Šablona tak jak je napsaná
nefunguje se selecty, nenastaví správné option selected.
Jediný způsob na který jsem přišel je tento, ale nevím, jestli je to
správně, popř. to nelze řešit lépe:
{formContainer items_detail_form}
{formContainer items_detail_form_$item->id}
{php $_form->setDefaults($item)}
{input id}
{input name}
{input save}
{/formContainer}
{/formContainer}
- flamengo
- Člen | 135
Ahoj, řeším banální případ a nějak se nemůžu pohnout z místa.
Potřebuji, aby mi grid držel proměnnou, protože ho načítám Ajaxem.
Proměnnou potřebuji mít ve stránkování, filtrování, sortingu atd. Zkusil
jsme persistentní proměnnou, ale asi to celé chápu nějak
špatně, protože v odkazech pro stránkování atd. se mi proměnná
pokus
neobjeví.
class MojeKomponenta extends Control
{
protected $model;
protected $dataGridFactory;
/** @persistent */
public $pokus;
public function __construct($model, $dataGridFactory)
{
$this->model = $model;
$this->dataGridFactory = $dataGridFactory;
$this->pokus = 'nastaveno';
}
public function createComponentGrid()
{
$grid = $this->dataGridFactory->create($this);
$grid->setDataSource($this->model->getAll());
$grid->addColumnText('name', 'Name');
return $grid;
}
}
Předem díky moc za nasměrování, určitě to bude jako vždy nějaká blbost.
Editoval flamengo (13. 11. 2019 18:41)
- dTTb
- Člen | 30
Ahoj,
- na https://contributte.org/…actions.html je pouzity <strong> pro zvyrazneni v prikladech zdrojaku, ale zobrazuje se tag:
<?php
$this->redrawControl('flashes');
<strong>$this['actionsGrid']->redrawItem($id);</strong>
?>
- Je nejaka moznost, jak pri pouziti allowRowsAction zobrazit text – vysvetleni proc dana akce u konkretniho radku neni povolena?
@flamengo persistentni promeny se ukladaj do url, ale ta se ti pri pouziti ajaxu nemeni. Nevim uplne kam miris, ale nepomohlo by ji ukladat do session?
- Pavel Janda
- Člen | 977
@dTTb
- Díky, fixed.
- Momentálně to bohužel nelze, ale je to zajímavá feature, PR bych se nebránil.
- Díky, mrknu na to
- Felix
- Nette Core | 1197
dTTb napsal(a):
A jeste na https://contributte.org/…ne-edit.html#… chybi v dokumentaci obrazky.
Obrazky uz jsou funkcni.
- xsuchy09
- Člen | 6
Petr Daňa napsal(a):
Ahoj, díky za super komponentu, aktualizuju jednu historickou aplikaci na Nette 2.4 (časem na 3.0, ale to až později), takže jsem hledal náhradu za Grido :) Potřeboval bych poradit s jednou specialitou, jestli to vůbec nějak půjde, klidně i za cenu hacku přímo v kódu Datagridu (v Gridu jsem to taky tak nakonec musel udělat). A sice mít možnost nastavit, že se vůbec nebudou načítat data, pokud je filtr prázdný. Zkoumal jsem zdrojový kód (verze 5.7.1 pro Nette 2.4), ale ikdybych vytvořil potomka DibiFluentDataSource, abych upravil getData(), tak tam nemám jak zjistit, jestli ten filtr je prázdný nebo ne. Takže jediné, co bych asi aktuálně mohl udělat je upravit přímo DataModel a ve filterData() si přidat podmínku pro volání datasource->getData(). Nebo existuje jiný (a správnější) způsob, jak toho docílit? Díky za pomoc.
EDIT: respektive asi dát rovnou podmínku na začátek filterData() a pokud je filtr prázdný, tak vrátit rovnou prázdné pole.
EDIT2: hm, tak to nefunguje, jsem v koncích :(
Řešil jsem podobnou potřebu a jde to vcelku jednoduše. DataGridu můžeš nastavit template a v něm můžeš přepisovat/přenastavovat původní bloky. Před nastavením template tak stačí podmínky
<?php
if ($dataGrid->isFilterActive() === true) {
$dataGrid->setTemplateFile(__DIR__ . '/templates/dataGrid.latte');
} else {
$dataGrid->setTemplateFile(__DIR__ . '/templates/dataGrid.empty.latte');
}
?>
a v empty šabloně pak stačí přepsat tbody:
<?php
{extends $originalTemplate}
{define tbody}
<tbody n:snippet="tbody">
<tr>
<td colspan="{$control->getColumnsCount()}">Nastav filtr</td>
</tr>
</tbody>
{/define}
?>
Tak dokud není nastaven filtr vykreslí se DataGrid bez dat.
Já ještě řeším potřebu omezit výpis na max. x záznamů – to ale nepůjde asi jinak, než nastavit natvrdo počet záznamů na stránku a skrýt stránkování (tedy zobrazit pouze první stránku a stránkování skrýt např. pomocí CSS).
Editoval xsuchy09 (27. 11. 2019 17:14)
- jannemec
- Člen | 78
Ahoj, mám trochu problém – u nette 3.0.2 mi datagrid stále hlásí
chybu
Datagrid needs to be attached to presenter in order to get its full name.
Vytvářím ho přes továrničku
class SimpleTasksDatagridFactory {
/** @var \Model\BlueLife\BlueLifeORM */
private $bluelifeService = null;
public function __construct(\Model\BlueLife\BlueLifeORM $blueLifeService =
null){
$this->bluelifeService = $blueLifeService;
}
public function create(int $userId = 0): \Controls\SimpleTasksDatagrid {
return new SimpleTasksDatagrid($userId, $this->bluelifeService);
}
}
a samotná definice je
class SimpleTasksDatagrid extends \Ublaboo\DataGrid\DataGrid {
/** var int */
protected $userId = 0;
/** \Model\BlueLife\BlueLifeORM */
protected $blueLifeService = null;
public function __construct(int $userId = 0, \Model\BlueLife\BlueLifeORM $blueLifeService = null) {
$this->userId = $userId;
$this->blueLifeService = $blueLifeService;
$this->setDataSource($this->blueLifeService->getUserSimpleTasks($this->userId), true, false);
//$grid->setDataSource($this->db->select(‚*‘)->from(‚ublaboo_example‘));
$this->addColumnText(‚name‘, ‚Name‘)->setSortable(true);
$this->addColumnText(‚description‘,
‚Description‘)->setSortable(true);
…
A už jsem v koncích …
- MasterPK
- Člen | 6
Ahoj, mám datagrid, kde je více sloupců a jeden je upravitelný s setEditableCallback na jinou funkci. Po přepsání hodnoty v datagrid a kliknutí bokem se vše spustí a nová data se zapíší do databáze, což funguje správně, ale v konzoli se vypíše chyba:
`Uncaught TypeError: this.handleXHR is not a function
at ajax (nette.ajax.js:225)
at submit (datagrid.js:642)
at HTMLTextAreaElement.<anonymous> (datagrid.js:672)
at HTMLTextAreaElement.dispatch (jquery.min.js:2)
at HTMLTextAreaElement.v.handle (jquery.min.js:2)`
<?php
public function createComponentTaskStudentsGrid($name)
{
$grid = new DataGrid($this, $name);
$grid->setPrimaryKey('id_user');
$grid->setDataSource($this->database->query("SELECT id_user, email, first_name, surname, points FROM user NATURAL JOIN student_has_task WHERE id_task = ?", $this->id_task)->fetchAll());
$grid->addColumnText('email', 'Email studenta')
->setSortable()
->setFilterText();
$grid->addColumnText('first_name', 'Jméno studenta')
->setSortable()
->setFilterText();
$grid->addColumnText('surname', 'Přijmení studenta')
->setSortable()
->setFilterText();
$grid->addColumnText('points', 'Body')
->setSortable()
->setEditableCallback([$this,"handleTaskPoints"]);
$grid->setTranslator($this->dataGridModel->dataGridTranslator);
return $grid;
}
public function handleTaskPoints($id_user,$value)
{
$httpRequest = $this->getHttpRequest();
$id_task = $httpRequest->getQuery('id_task');
$maxpoints = $this->database->query("SELECT task_points FROM task WHERE id_task = ?", $id_task)->fetch();
if($maxpoints->task_points >= $value)
{
$this->database->query("UPDATE student_has_task SET points = ? WHERE id_user = ? AND id_task = ?", $value, $id_user, $id_task);
}
}
?>
A poté již daná položka nejde upravit. Neví někdo co to způsobuje? Děkuji za pomoc.
- jannemec
- Člen | 78
@n3t BINGO – díky moc … akorát to ve verzi 3.0 hodí
následně jinou chybovou hlášku, protožer se registruje dvakrát … musel
jsem v constructoru datagridu zakomentovat
if ($parent !== null) {
$parent->addComponent($this, $name);
}
základ funguje, ale v javascript konzoli se objevuje stejná chyba jako píše @MasterPK „Uncaught TypeError: this.handleXHR is not a function“
- nanuqcz
- Člen | 822
Ahoj,
snažím se v projektu rozjet DataGrid, ale nedaří se. Zkusil jsem tedy
postupovat přesně podle dokumentace na čistém nette/web-project, a
i přesto Datagrid nefunguje:
- Přestože jsem natáhl všechny JS+CSS závislosti dle dokumentace, chybí ikona v tlačítku.
- Po kliknutí na tlačítko, místo aby se zobrazil řádek pro inline vložení záznamu, se celá stránka jen refreshne a nic jiného se nestane.
- V konzoli jsou chyby ohledně některých chybějících JS knihoven, přestože jsem při jejich instalaci přes bower postupoval dle Datagrid dokumentace.
Můj pokus na nette/web-project si můžete prohlédnout zde:
https://gitlab.com/…/contributte
Jak to mám prosím udělat, aby mi Datagrid fungoval?
Děkuji za rady.
Editoval nanuqcz (9. 12. 2019 15:18)
- Tomáš Vodička
- Člen | 28
Myslím že problém je v cestě, JS a CSS linkuj pomocí
proměnné {$basePath}
např.
<link rel="stylesheet" type="text/css" href="{$basePath}/bower_components/bootstrap/dist/css/bootstrap.css">
- nanuqcz
- Člen | 822
@IJVo Díky za radu :-) Která ale vedla k další chybě:
Uncaught SyntaxError: Unexpected token ‚export‘ in Happy.js:224
Dovede tu vůbec někdo rozchodit Datagrid v aktuální verzi? Zkusím nainstalovat verze starší, tohle je dost divné…
Nějaké další rady prosím? :-( Připomínám, že jde o čisté nette/web-project a že jsem přesně dodržoval instrukce v dokumentaci.
- nanuqcz
- Člen | 822
Tak vypadá to, že jakoukoli verzi 5.* rozjedu bez problémů.
Verzi 6.* ale ne. Jakto?
Pro kterou verzi je psaná dokumentace na https://contributte.org/…te/datagrid/ ?
EDIT: Tak dokumentace na webu je pro datagrid verzi 6 (která nejde rozjet). Dokumentace k verzi 5, kterou lze nalézt na githubu, zase není kompletní (chybí např. základní instrukce k instalaci).
Samotné Demo datagridu běží taky na verzi 5. Což lze poznat
třeba z datagrid.js
suboru, které demo aplikace načítá (demo vs verze 6)
Editoval nanuqcz (10. 12. 2019 13:17)