ublaboo/datagrid: mocný, rychlý, rozšiřitelný, hezký, anglicky dokumentovaný datagrid

David Grudl
Nette Core | 8218
+
+1
-

Pavel Janda napsal(a):

Píšu si issue – nastavení defaultních hodnot filtru.

Aha, myslel jsem, že k tomu slouží $grid->setFilter(['filterName' => 'value']), což mi funguje, ale pravda, slovo default by v názvu bylo popisnější.

Nějaké nápady na ověřenou JS knihovnu, která zpříjemní práci s multiselectem?

Používám Select2. Jeho chování je pro multiselect s tolika položkami, že při rozkliknutí nejsou vidět všechny najednou, ideální.

TomasG
Člen | 23
+
0
-

Ahoj,
prvně bych chtěl říct, že tento grid je přímo excelentní :o)
a dále mám menší dotaz:
Mám problém s překladem confirmů u akcí (používám Kdyby\Translation).
ve slovníku mám

...
	confirm:
		delete: 'Opravdu chcete odstranit roli %name%?'

Ale nevím jak tam poslat ten parametr %name%.
Klasicky přes ->setConfirm('confirm.delete', 'name'); se tam parametr nedostane. V případě callbacku si můžu zprávu přeložit sám ve funkci, ale jelikož má grid nastavený translator, tak se pořád snaží i ten výsledný confirm přeložit sám.

Pavel Janda
Člen | 977
+
+1
-

@DavidGrudl DataGrid::setFilter() je násilné nastavení filtru. Tedy i pokud uživatel změní hodnoty filtru a později přijde na stejný grid, bude ten filtr nastavený tak, jak chce metoda setFiter() přesto, že je třeba uloženo něco jiného v session.

Něco jako DataGrid::setDefaultFilter() by pak nemělo přepisovat případná data v session. Rozepíšu to potom v dokumentaci, ať je to jasné.

@TomasG To je bug. Do překladače by se samozřejmě měl hnát jen ten string s dynamickým placeholderem. Je to fixnuté, zatím v masteru. Pokud je v confirmation dialogu nastaven callback, měl by vracet již přeložený string.

Editoval Pavel Janda (19. 4. 2016 12:06)

tatyalien
Člen | 239
+
0
-

@PavelKouřil: já používám multiselect

TomasG
Člen | 23
+
0
-

@PavelJanda Díky :o)

David Grudl
Nette Core | 8218
+
+4
-

Ještě pár věcí:

  • když vypnu stránkování $grid->setPagination(FALSE), asi by se nemusel zobrazovat spodní panel row-grid-bottom, kde vlastně nic není (a možná by mohl být renderován jako řádek tabulky, aby byl stejně široký, když tabulka nemá width: 100%)
  • u aktivování $('.datagrid [data-sortable]') by bylo fajn přidat option axis: 'y' a taktéž ikonu změnit z fa-arrows na fa-arrows-v
  • if (typeof $('.datagrid [data-sortable]').sortable === 'undefined') { dělá zbytečný dotaz nad DOM, stačí if (typeof $.fn.sortable === 'undefined') {
  • ačkoliv dokumentace trošku (a asi nechtě) naznačuje opak, tak datagrid.js musí být natažen až na konci stránky. Nestálo by za to ty inicializace nad DOM přesunout do $(function() { … })?
David Grudl
Nette Core | 8218
+
+3
-

Trik, jak zamezit, aby se přesouvanému řádku nezměnily šířky sloupců:

return $('.datagrid [data-sortable]').sortable({
	helper: function(e, ui) {
		ui.children().each(function() {
			$(this).width($(this).width());
		});
		return ui;
	},
	…
Pavel Janda
Člen | 977
+
0
-

@DavidGrudl Stránkování: Je tam ještě třeba někde zobrazit button, který umožní resetování filtru. Přidám do šablony podmínku (nepoužívám filtry && nepoužívám stránkování ⇒ skryj patičku).

Zapřemýšlím nad tím řádkem tabulky. Dřív tam byl nějaký problém ohledně snippetů, ale už to myslím není aktuální.

Díky za poznámky. Do masteru jsem dal pozměněné assety.

David Grudl
Nette Core | 8218
+
+1
-

Díky, super práce!

sepo
Člen | 69
+
+1
-

Pavel Janda napsal(a):

Nová verze – v3.3.0

Ahoj
„plus“ button je v hlavičke a riadok pridáva na koniec
je možné ho renderovať ako prvý riadok/resp. do hlavičky ?

Pavel Janda
Člen | 977
+
0
-

@sepo Dobrý nápad. Zatím v masteru, bude v příští verzi. Api: $grid->addInlineAdd()->setPositionTop();, opětovaného nastavení renderování dole je docíleno toutéž metodou, akorát s argumentem FALSE.

darkweaver
Člen | 18
+
0
-

Ahoj, prvně bych chtěl poděkovat za parádní DataGrid, je opravdu super. Chtěl bych se ale zeptat, jakým způsobem zpracováváte chyby vzniklé při inline editaci/přidávání nové položky přes DataGrid?

Když datagrid umožňuje přidávání/editaci přímo v tabulce, a vypisovaných dat je málo(cca 3 sloupečky), tak mi přišlo zbytečné přidávat další stránku jen pro přidávání/editaci záznamů dané entity.

Jak ale řešíte situaci, kdy na jednom sloupci je nastaven například unique key, nebo hodnota v jednom sloupci nesmí být větší než hodnota v druhém sloupci apod.?

Normálně mi z aplikace přijde například vyjímka, kterou bych zpracoval a vyhodil flash message. Jak ale takovou chybu zobrazit? Zobrazit flash message nad datagridem? Když bude počet položek na jedné stránce větší, tak flash message nad datagridem a položka někde dole nebude moc user friendly.

Zkoušel jsem i hodit formulář do detailu položky, což se mi povedlo, ale nepřišel jsem už na to, jak tam dostat defaultní hodnoty zobrazované entity, pokud by to ale šlo, jak bych tam mohl zobrazit tu chybovou zprávu?

Nebo se na to dívám úplně špatně a měl bych v inline editaci povolit pouze změnu hodnot, u kterých k takové chybě nedojde?

Díky moc za odpovědi.

Pavel Janda
Člen | 977
+
+1
-

@darkweaver Nad složitějšími chybovými hláškami jsem zatím nepřemýšlel. Používají se ale nette forms, takže validační pravidla by se měla aplikovat již v JS. Ale za jakýkoliv další nápad budu rád.
Na druhou stranu, vyrábění nějaké větší entity přes inline přidávání záznamů v datagridu mi přijde trochu hardcore.. Ale jak říkám, nebráním se dalším nápadům, jak takové počiny zpříjemnit.

Inline přidávání záznamů je momentálně jediná věc, která se netahá pomocí snippetu. Kdyby se tahala, tak by tam asi šly dostat normální formulářové ajaxové validace. Zatím jsem nepřišel na způsob, jak toho docílit v té tabulce. Možná na to ještě přijdu.

Defaultní hodnoty ve velké inline editaci nastavíš pomocí eventu InlineEdit::onSetDefaultshttp://ublaboo.paveljanda.com/datagrid/edit#…

Defaultní hodnoty ve formuláři detailu položky můžeš nastavit v šabloně, http://ublaboo.paveljanda.com/datagrid/action#…

David Grudl
Nette Core | 8218
+
+1
-

Ještě k těm přesouvacím ikonkám – viděl jsem, že teď se ikonka při přesouvání změní z 🕂 na ↕ což mi ale úplně nedává smysl, respektive nerozumím, proč mít vůbec pro přesun nahoru/dolů ikonku 🕂 znamenající přesun ve všech směrech?

Určitý problém z hlediska UI je také zobrazení této ikonky v podobě buttonu, protože to tlačítko není, je to prostě táhlo, viz třeba použití na https://jqueryui.com/sortable/. Chápu, že důvodem asi je snaha o jednotný vzhled ikon v sloupci Action, ale toho bych se vůbec nebál, odstranění tlačítka (obrázek vlevo) na vzhledu neubírá a na srozumitelnosti určitě přidá (fa fa-arrows-v fa-lg):

Pavel Janda
Člen | 977
+
0
-

@DavidGrudl 2, Souhlasím, že se to nechová jako klasické tlačítko. Na druhou stranu, značí to nějakou akci – když kliknu (podržím), něco se stane. Pouze ikonka tak, jak je na screenshotu nalevo, se mi nezdá tak proaktivní jako napravo.

1, Taky bych s tím souhlasil. Ale obyčejní lidé jsou spíš zvyklí na symbol té čtyřšipičky, alespoň na mě působí spíš jednoduchým dojmem „přesunou“, než „Vzít, táhnout – proč to nejde od všech stran??“..

Udělám s pár lidmi nějaký jednoduchý testing, abych získal náhled ze strany bfu.

Dík za postřehy

Editoval Pavel Janda (20. 4. 2016 14:14)

Jakub Kontra
Člen | 30
+
0
-

David Grudl napsal(a):

Ještě k těm přesouvacím ikonkám – viděl jsem, že teď se ikonka při přesouvání změní z 🕂 na ↕ což mi ale úplně nedává smysl, respektive nerozumím, proč mít vůbec pro přesun nahoru/dolů ikonku 🕂 znamenající přesun ve všech směrech?

Určitý problém z hlediska UI je také zobrazení této ikonky v podobě buttonu, protože to tlačítko není, je to prostě táhlo, viz třeba použití na https://jqueryui.com/sortable/. Chápu, že důvodem asi je snaha o jednotný vzhled ikon v sloupci Action, ale toho bych se vůbec nebál, odstranění tlačítka (obrázek vlevo) na vzhledu neubírá a na srozumitelnosti určitě přidá (fa fa-arrows-v fa-lg):

Pavel Janda napsal(a):
@DavidGrudl 2, Souhlasím, že se to nechová jako klasické tlačítko. Na druhou stranu, značí to nějakou akci – když kliknu (podržím), něco se stane. Pouze ikonka tak, jak je na screenshotu nalevo, se mi nezdá tak proaktivní jako napravo.

1, Taky bych s tím souhlasil. Ale obyčejní lidé jsou spíš zvyklí na symbol té čtyřšipičky, alespoň na mě působí spíš jednoduchým dojmem „přesunou“, než „Vzít, táhnout – proč to nejde od všech stran??“..

Udělám s pár lidmi nějaký jednoduchý testing, abych získal náhled ze strany bfu.

Dík za postřehy

Souhlasím s @DavidGrudl. Varianta v levo (táhlo) je více uživatelsky přívětivá a určitě bych to tak rád viděl. Není tlačítko jako tlačítko

David Grudl
Nette Core | 8218
+
0
-

Pavel Janda napsal(a):

Udělám s pár lidmi nějaký jednoduchý testing, abych získal náhled ze strany bfu.

To je nejlepší cesta, paráda.

Šaman
Člen | 2659
+
+1
-

Zrovna teď jsem to řešil a výsledkem je levé řešení. Ale dát ikonu dvojšipky na tlačítko by taky šlo. Čtyřšipka mě ani nenapadla a přijde mi méně jasná.

Pavel Janda
Člen | 977
+
0
-

@tatyalien K tomu bitbucketu: Úplně nevím, co všechno máš v plánu s tou třídou ExampleFilter, ale v podstatě může tvoje Repository rovnou implementovat Ublaboo\DataGrid\DataSource\IDataSourcehttp://pastebin.com/LLcZ8uDe

Editoval Pavel Janda (27. 4. 2016 12:10)

daliborK
Člen | 3
+
0
-

Zdravím děkuji za skvělý Datagrid, opravdu vymakaný :-).
Potřeboval jsem do horní části grida vedle ikonek „Nový záznam“ a „Skrýt sloupce“ přidat ještě jednu mnou definovanou (nějaký odkaz). Rozšířil jsme si třídu \Ublaboo\DataGrid\DataGrid a přidal metodu

<?php
class Grid extends \Ublaboo\DataGrid\DataGrid {

    protected $settingButtons;

    public function __construct($parent, $name) {
        parent::__construct($parent, $name);
    }
    /**
     * muzes pridat element a zobrazi se v horni casti grida
     * @param \Nette\Utils\Html $el
     */
    public function addSettingButtons(\Nette\Utils\Html $el=null){
	    if($el){
	        $this->settingButtons[] = $el;
	    }
	    return $this;
    }

    public function render() {
	    $this->template->settingButtons = $this->settingButtons;
	    parent::render();
    }
}
?>

a v šabloně upravit podmínky nad vykreslením $inlineAdd přidal toto:

<?php
{if $settingButtons}
    {foreach $settingButtons as $button}
		{$button}
    {/foreach}
{/if}
?>

Poté se dá použít takto:

<?php
...
$grid->addSettingButtons(\Nette\Utils\Html::el('a')
        ->href('print:pdf')
        ->setText('Tisk pdf')
    );
?>

Co něco podobného přidat přímo do \Ublaboo\DataGrid\DataGrid?

Pavel Janda
Člen | 977
+
0
-

@daliborK Určitě je to zajímavý nápad. Můžeš to poslat v PR? :)

tatyalien
Člen | 239
+
0
-

@PavelJanda
Ahoj, díky za nástřel, koukal jsem na to a zkusil to implementovat, ale dostávám Fatal error: datagrid/src/DataSource/ArrayDataSource.php:221 přitom ale mám nastavený dataSource na tu repository. Akutalizoval jsem bitbucket, konkrétně:

  • presenter: createComponentExamplesGrid($name)
  • repository: udělaný jen nástřel dle tebe
Pavel Janda
Člen | 977
+
0
-

@tatyalien Co se ti hází za chybu? Kdyžtak mi všechno piš prosím na gitter. Btw, pokud chceš používat jako datasource tu repositoru, tak nepiš $grid->setDataSource($this->exampleRepository->getData());, ale $grid->setDataSource($this->exampleRepository);.

tatyalien
Člen | 239
+
0
-

Pavel Janda napsal(a):

@tatyalien Co se ti hází za chybu? Kdyžtak mi všechno piš prosím na gitter. Btw, pokud chceš používat jako datasource tu repositoru, tak nepiš $grid->setDataSource($this->exampleRepository->getData());, ale $grid->setDataSource($this->exampleRepository);.

Ahoj,
napsal jsem ti email, gitter neznám :) tak ať to tu nespamuji.

romiix.org
Člen | 343
+
0
-

@PavelJanda Vybral si nejaký multiselect? Kedy ho máš cca na pláne implementovať? Potrebujem ho a ak by som sa k nemu dostal skôr ako ty, tak nech pošlem rovno PR s doplnkom ktorý chceš aj ty.
Vďaka!

Pavel Janda
Člen | 977
+
+1
-

@romiix.org Už je to pár dní v masteru. Otaguji to ve verzi 4.0.0 během dneška/zítřka.

romiix.org
Člen | 343
+
0
-

Pavel Janda napsal(a):

@romiix.org Už je to pár dní v masteru. Otaguji to ve verzi 4.0.0 během dneška/zítřka.

Vidím správne, že nie je použitý žiadny JS doplnok?
Tzn. filtrovací riadok sa proste natiahne a zobrazí sa štandardný HTML multiselect.

Edit: Používa sa bootstrap-select.

Editoval romiix.org (2. 5. 2016 11:15)

Pavel Janda
Člen | 977
+
+1
-

@romiix.org Ano, používá se bootstrap-select. Vše bude popsáno v docu v moment, co vydám v4. :)

romiix.org
Člen | 343
+
0
-

Je možné použiť vlastné zoradenie riadkov, ktoré neexistujú v DB?

Konkrétne: Ceny produktov sú dynamické a počítajú sa na základe mnohých parametrov. Nie je problém ich vypísať cez setRenderer(), ale neviem ich zoradiť podla dodatočne vypočítanej hodnoty.
->setSortableCallback() mi nefunguje, resp. neviem ako metódu použiť.

Skúšal som to nasledovne:

$grid->addColumnText('price', 'itemsGrid.price')
	->setSortable()
	->setSortableCallback(function($datasource, $sort) {
		$datasource->order('FIELD(id, ?)', $this->itemModel->sortByPrice($datasource, $sort['price']));
	});

Je to aktuálne riešiteľné?

Vďaka!

@PavelJanda Vlastne to funguje :) Vyriešené.

Editoval romiix.org (2. 5. 2016 17:56)

Pavel Janda
Člen | 977
+
+1
-

@romiix.org http://ublaboo.paveljanda.com/datagrid/column#…

Tedy například:

$grid->addColumnNumber('id', 'Id')
	->setSortable()
	->setSortableCallback(function($fluent, $sort) {
		$fluent->orderBy('name DESC');
	})

Editoval Pavel Janda (2. 5. 2016 15:20)

romiix.org
Člen | 343
+
+1
-

Pavel Janda napsal(a):

@romiix.org http://ublaboo.paveljanda.com/datagrid/column#…

Tedy například:

$grid->addColumnNumber('id', 'Id')
	->setSortable()
	->setSortableCallback(function($fluent, $sort) {
		$fluent->orderBy('name DESC');
	})

Toto funguje, ak sa sort vykonáva ajaxovo prostredníctvom handleSort(). V tento metóde sa zavolá

$this->sort_callback = $column->getSortableCallback();

a nad tým istým objektom sa zavolá render().

Dostal som sa k tomu, že ak je v session nastavené zoradenie, tak sa sortable callback nezavolá, pretože sa nenastaví do $this->sort_callback.

PR s fixom

Editoval romiix.org (2. 5. 2016 19:48)

Pavel Janda
Člen | 977
+
+5
-

Nová verze – v4.0.0

Vydal jsem novou verzi, kvůli změně latte šablony považuji novou verzi za možný bc break, více v posledním bodu seznamu níže.

Díky všem za nápady a spolupráci!

Editoval Pavel Janda (4. 5. 2016 9:43)

Pavel Janda
Člen | 977
+
+1
-

A ještě jedna věc: přibyl nový datasource: ApiDataSource. Je experimentální a netestoval jsem ho. Pokud ho někdo využije, piště, co přidat/zlepšit. Moc tam toho asi nebude. ApiDataSource prostě forwarduje filtrování, sortění a pod na remote api.

daliborK
Člen | 3
+
0
-

Zdravím trochu zápasím s inline editací:

  1. je možné po kliku na tlačítko „save“ překreslit celý dataGrid a né jenom konkrétní řádek? Zkoušel jsem obalit dataGrid do snippetu a zavolat $this->redrawControl(), ale poté se zobrazí pouze editovaný záznam.
  2. do formuláře inline editace bych potřeboval dostat něco jako $form->addError(‚xx‘). V podstatě zabránit uložení a zobrazit chybovou hlášku. Je to možné?

Děkuji za jakýkoli nápad.

Pavel Janda
Člen | 977
+
0
-

@daliborK

  1. Momentálně ne, onSubmit event se triggeruje před překreslením řádku, takže moc do datagridu v tu chvíli šáhnout nelze. Můžeš založit issue.
  2. Už je založena issue s validací inline formuláře.
daliborK
Člen | 3
+
0
-

OK, děkuji za info

Ripper
Člen | 56
+
0
-

Zdravím všechny,

rád bych se zeptal zda někdo nemáte slušně udělaný handle na sort (ukládání seřazených prvků). Trochu s tím zápasim, jakš takš mi to funguje, ale má to asi 45 řádků a vůbec se mi to nelíbí. Proto se obracím na ty zkušenější, zda by někdo nenabídl svůj snippet.

Díky za odpovědi, rady. Ripper.

fizzy
Backer | 49
+
+2
-

@Ripper akurat sme to tiez riesili, najednoduchsie co ma napadlo:

public function handleSort($item_id, $prev_id, $next_id){
		$prevRow = $this->database->table("tabulka")->where("id", $prev_id)->fetch();
		$newOrderId = $prevRow ? $prevRow->position + 1 : 1;
		$this->database->query("UPDATE tabulka SET position = position + 1 WHERE position >= ?", $newOrderId);
		$this->database->query("UPDATE tabulka SET position = ? WHERE id = ?", $newOrderId, $item_id);
	}
pitr82
Člen | 121
+
0
-

Mám dotaz,
pokud používam změnu stavu pro řádek (status), již se mi nezmění css třída, která v mém případě obarvuje řádek.
Zavolá se onChange[], kde se provede redraw řádku provede se změna stavu, a pak se vola setRowCallback() kde se změní class prvku na základě stavu, ale už se neaplikuje redraw řádku.
Jak docílit, aby se změnila i class prvku ?

$grid->setRowCallback(function($item, $tr) {
	$tr->addClass('super-' . $item->id);
	$this['columnsGrid']->redrawItem($id);
});
Pavel Janda
Člen | 977
+
0
-

@pitr82 Hmm, to je trošku trouble. Bohužel, momentálně je v kódu <tr n:snippet="item-...">, takže se překresluje pouze obsah elementu <tr>. A obalit <tr> snippetem nelze, protože samotný snippet vytvoří div a <tbody> nesmí obsahovat přímo div. :P

Dáš to pls na github do issues? Nějak to vymyslíme.

sibka
Člen | 24
+
0
-

@PavelJanda Opět musím pochválit vývoj gridu.

Ale bohužel mi po upgradu nefunguje nastavení výchozího filtru. Mám:

$grid->setDefaultFilter(array(‚datum‘ => –2),true);
$grid->addColumnDateTime(‚datum‘, ‚Datum‘)
->setFilterSelect(…

A píše mi to „Filter [datum] is not defined“.

Omlouvám se za kód, nějak mi to nejde pěkně vložit.

Editoval sibka (12. 5. 2016 7:44)

Pavel Janda
Člen | 977
+
0
-

@sibka dej definici sloupce/filtru pred ty defaultni hodnoty. Je tam check, aby to spis vyvojare nutilo napsat spravne klice defaultnich hodnot, nez aby to v tichosti proslo a nic se pak nezobrazilo.

sibka
Člen | 24
+
0
-

@PavelJanda Super díky, už to šlape.

romiix.org
Člen | 343
+
0
-

Je aktuálne nejak možné zakomponovať závislé filtre?
Konkrétne by som potreboval, aby sa dalo pri plnení filtrov dalo pristúpiť k odfiltrovanému datasourcu na základe predošlého vyplnenia. Tzn. zaškrtnem výrobcu Toyota a ponúkne mi iba autá zodpovedajúce danému výrobcovi, atď.

Pre nastavenie korektných hodnôt je potrebné mať k dispozícií aktuálny zoznam odfiltrovaných áut. To by bolo riešiteľné vyňatím zodpovednej sekvencie z render metódy do novej metódy getRows. Metóda je dostupné v továrničke a vieme zobrazovať položky na základe zostávajúcich možností.

Zložitejší problém je, ako aktualizáciu filtra zobraziť. Dalo by sa pridať snippet pre riadok s filtrami, ale to by spôsobilo nepríjemný problém pri multiselecte – po označení niektorej položky by sa výber skryl. To by sa asi dalo riešiť snippetmi na úrovni <ul> elementov. Je tento prístup správny? Nejaký iný nápad..?

romiix.org
Člen | 343
+
0
-

@PavelJanda Je v pláne nejaký suggest input filter?

Pavel Janda
Člen | 977
+
+1
-

@romiix.org Není. Ale není problém si ho přidat. Prostě přidej inputu filtru třídu, nebo data atribut a vyrob si nějaké api, kde budeš předávat data z (pravděpodobně) databáze.

Nic takového ale implementovat neplánuti. Proč:

  1. Je to megajenoduché implementovat s vlastní oblíbenou suggest knihovnou
  2. Jelikož se všechna data filtrují ajaxově a v reálném čase, přijde mi suggest zbytečný.

K těm závislým filtrů: Já osobně bych to tady asi řešil spíš pomocí dalšího formuláře, který by byl nad datagridem a sám bych mu předával filtrovaný datasource. Ale jak jsi psal, není to problém nějak ohnout, problém je to ohnout tak, aby ti nezmizel focus z toho pole.

Editoval Pavel Janda (15. 5. 2016 14:44)

FJP
Člen | 124
+
0
-

Ahoj,
když dám více gridů za sebe (mám u produktu seznam fotek a seznam souborů) a používám hromadnou akci – u druhého gridu dám zaškrnout všechny položky, zaškrtnou se všechny i v prvním gridu + se nezobrazí button v příslušeném gridu, ale ukáže se v tom předchozím.

Pavel Janda
Člen | 977
+
+1
-

@FJP :D Pani to je slozity! Fixnu, jen co se dostanu domu.

Pavel Janda
Člen | 977
+
+2
-

Nová verze – v4.1.0

Editoval Pavel Janda (18. 5. 2016 18:57)

FJP
Člen | 124
+
0
-

Stáhnul jsem novou verzi a chová se mi to trošku podivně:

Pozn: chová se to stejně i když jsou v gridu nějaké řádky

Editoval FJP (19. 5. 2016 9:51)