Nextras\Datagrid – datagrid se vsim jak ma byt
- hrach
- Člen | 1838
Nextras\Datagrid
Výhody oproto ostatním:
- konečně použitelné API
- vzhled, filtry a helpery píšete v šabloně, ne v PHP
- complete lazy – používá callbacky
- inline editace!
- full AJAX podpora (přenáší se jen to, co je třeba, tzn. třeba jen jeden řádek tabulky.) – podpora moderniho nette.ajax.js
- plna podpora Nette\Database pristupu – tedy zadne joiny!
Odkazy:
Demo je zatim male, protoze nevyuziva dalsi komponenty. V tom je sila Nextras\Datagridu – mate vlastni komponentu na datum? Proc ne, pouzijte si ji. Mate vlastni komponentu na Ajax vyhledavani? Proc ne, pouzijte si ji. Nextras\Datagrid vam neklade zadny odpor. Pouzvejte sve vlastni komponenty! Definujte si svuj vlastni vzhled.
Editoval hrach (21. 3. 2013 9:50)
- David Ďurika
- Člen | 328
mozem potvrdit je to Datagrid 2.0 :)
super napad s tym setDataSourceCallback
takto som tam vedel jednoducho rozbehat aj doctrine2!
- David Ďurika
- Člen | 328
@o5 design je s bootstrapu…
@hrach bolo by fajn kedy si do zakladnej sablony zapracoval hned tie bootstrap prvky, potom by si nic s tohto robit a nam zjednodusil zivot :) a ak niekto nebude chciet pouzit bootstrap (tak ho vystavis do muzia) tak si to jednoducho prepise…
Editoval achtan (30. 12. 2012 18:29)
- hrach
- Člen | 1838
- Ne, urcite nechci aby bootstrap vzhled byl vychozi.
- Tuto nevyhodu castecne chcu vyresit tim, ze si budes moci nadefinovat vice sablon s temi blocky, takze muzes mit vlastni komponentu, ktera bude automaticky includovat definice pro bootstrap tabulku.
- vzhled tabulky je vicemene bootstrapovsky. To, ze @o5 pouziva
v gridu nesmyslne tridy
.even
na tr a pak to styluje bokem v.grido tbody tr.even
je sice vysledkem stejne, ale mne stacilo pridattable-striped
. To stejne jakotable-condensed
a teoreticky itable-hover
, ktery tam neni. Jedine co je navic a musim se pravda priznat, ze inspirovane z grida je gradient v<thead>
. Na opaktu se doporucuji inspirovat v reseni width=100% za pomoci box-sizing, misto toho indentu ;)
- secmi
- Člen | 19
Ahoj,
snažím se pomocí toho datagridu přidat sloupec, který bude zobrazovat
sloupec z tabulky propojené pomocí cizího klíče, ale nedaří se mi.
Pokud použiji
$grid->addColumn('vozidla->rz', 'rz');
dostanu chybu PDOException – No reference found for $zakazky->vozidla->rz
Pokud však stejnou věc udělám takto
$grid->addColumn('vozidla', 'rz');
a pak v šabloně
{define col-vozidla}
<td>
{$row->vozidla->rz}
</td>
{/define}
tak je vše v pořádku.
Datacallback je
$selection = $this->connection->table('zakazky');
Tabulky mám provázané cizím klíčem z tabulky zakázky (CONSTRAINT
zakazky_ibfk_4
FOREIGN KEY (vozidla_id
) REFERENCES
vozidla
(vozidla_id
)), takže se obávám, že v tom
prvním případě na to jdu špatně…
Verze Nette je 2.0.8
Editoval secmi (5. 1. 2013 17:18)
- secmi
- Člen | 19
Super, díky moc!
V souvislosti s tím bych se ještě zeptal na jednu věc, jak vypsat více sloupců z tabulky vozidel (třeba vin, tp), tak aby sloupec měl normálně záhlaví, případně se mu dal přidat filtr…
Pokud přidám znovu
$grid->addColumn('vozidla', 'rz');
tak budu dva sloupce se stejným jménem, tzn. potřeboval bych přidat nějaký fiktivní sloupec, tak aby se nezařadil do selectu a já si ho následně upravil v šabloně. Nebo na to jdu úplně špatně?
- hrach
- Člen | 1838
Pokud má sloupec definovaný block, tak je uplně jedno, jak se jmenuje. Klidně to může být
$grid->addColumn('rz', 'RZ');
Takovému sloupci jde přiřadit filtrovací Control, nicméně obsah je
právě naplněn/předefinovám blockem define
. (Samozřejmě daný
block je patřičně pojmenován {define col-rz}
)
- secmi
- Člen | 19
To je právě to co mi nefunguje :(
Přidám sloupec, který je v provázané tabulce
$grid->addColumn('vin', 'vin')->enableSort();
v šabloně pak definuji co se má vypsat
{define col-vin}
<td>
{$row->vozidla->vin}
</td>
{/define}
ale skončím chybou PDOException – No reference found for $zakazky->vin.
Trošku jsem pátral a problém je podle mě na řádku 73 v Datagrid.latte
{var $cell = $control->getter($row, $column->name)}
kde probíhá pokus získání sloupce bez ohledu na to jaká je definice v šabloně a pokud tedy sloupec neexistuje, jako v tomto případě, skončí skript výše uvedenou výjimkou.
Takže kdyby se funkce getter v Datagrid.php upravila nějak takto
public function getter($row, $column)
{
if ($this->columnGetterCallback) {
return $this->columnGetterCallback->invokeArgs(array($row, $column));
} else {
try {
return $row->$column;
}
catch(\PDOException $e) {
return NULL;
}
}
}
měl by se celý problém vyřešit…
Editoval secmi (5. 1. 2013 21:51)
- Filip111
- Člen | 244
Ahoj, zprovoznil jsem grid a snažím se ušetřit si práci
v administraci.
Každá tabulka v administraci má stejné akce + něteré umí i něco
navíc. Mám tedy základní šablonu s akcemi
columns-default.latte:
{define col-actions}
<a href="{plink edit $primary}" data-datagrid-edit class="ajax btn btn-small btn-primary">Edit</a>
<a href="{plink delete! $primary}" class="btn btn-small btn-info">Smazat</a>
{/define}
a pak můžu mít u některých tabulek akce upravené a chtěl bych aby
přepsali tu půvdní definici, např.
columns-specific.latte:
{define col-actions}
<a href="{plink edit $primary}" data-datagrid-edit class="ajax btn btn-small btn-primary">Edit</a>
<a href="{plink delete! $primary}" class="btn btn-small btn-info">Smazat</a>
<a href="{plink setDef! $primary}" class="btn btn-small btn-info">Nastavit defaultní</a>
{/define}
Přidám je do cellTemplates:
$grid->addCellsTemplate('columns-default.latte');
$grid->addCellsTemplate('columns-specific.latte');
Problém je, že vidím stále akce definované v první šabloně, tedy columns-default.latte a nikoliv z té druhé. Definice bloku v latte se nedá přepsat pozdější deklarací stejného bloku? (pokud přehodím pořadí nastavení cellTemplates, zobrazí se správné akce…zkrátka vždy z té první definice define)
Pořadí ale změnit nemůžu:
V ModelAdminPresenteru si předpřipravím základní kompoentu:
$grid = new \Nextras\Datagrid\Datagrid;
$grid->setDataSourceCallback($this->getListData);
$grid->addCellsTemplate('columns-default.latte');
$this->grid = $grid;
// casem chci pridat spolecne prvky a funkce
a pak v konkrétním v presenteru, který dědí ModelAdminPresenter, ji jen doupravím:
public function createComponentListGrid() {
$grid = $this->grid;
$grid->addColumn('status', 'S');
$grid->addColumn('title', 'Název');
$grid->addColumn('weight', 'Hmotnost');
$grid->addColumn('categoryId', 'Kategorie');
$grid->addCellsTemplate('columns-specific.latte');
return $grid;
}
Editoval Filip111 (10. 1. 2013 11:52)
- hrach
- Člen | 1838
define blocky nelze bohuzel prepisovat ani dedit, nicmene nic ti nebrani si vytvorit vlastni block a ten si pak includnout.
{define col-actions}
{include #col-default-actions primary => $primary, row => $row}
{/define}
Bohužel je to omezeni nette, které aktuálně nechci nějak v Datagridem řešit.
- miler
- Člen | 75
Ještě jeden dotaz – používám gettextové překlady z plaNette, ty potřebuji nasadit např. na buttony u filtrů.
Zkoušel v setFilterFormFactoey jsem něco jako:
$form->getForm()->setTranslator($this->translator);
Při úpravách @Datagrid.latte zase pro změnu:
Call to undefined method Nette\Templating\FileTemplate::translate()
Děkuju moc za radu.
- hrach
- Člen | 1838
Tak, určitě si můžeš nadefinovat vlasntí edit tlačítko, tím padem
v kodu muzes nastavit u jeho prelozeny label. Chapu ze to neni idealni. Jakym
zpusobem propasovat tam translator, zamyslim se.
Stejne tak premyslim,jakym zpusobem nechat dodefinovat filtry a helpery pro
sablonu. Diky za feedback.
- lunak83
- Člen | 47
Aha, ono to bylo tak jednoduche! Diky!
I když teď jsem narazil na malý problém a to že při filtrování paginator zůstává stejný, tedy že jsem na straně 2/3 i když položka je prakticky jen jedna. Zároveň musím předat i řazení a filtr další stránce.
public function getDataLight($filter, $order) {
$filters = array();
foreach ($filter as $k => $v) {
$filters[$k . ' LIKE ?'] = "%$v%";
}
$selection = $this->table->where($filters);
$paginator = $this['paginator']->getPaginator();
$paginator->itemCount = $selection->count();
$paginator->itemsPerPage = 25;
if ($order) {
$selection->order(implode(' ', $order));
}
return $selection->limit($paginator->getLength(), $paginator->getOffset());
}
Editoval lunak83 (15. 1. 2013 16:47)
- David Ďurika
- Člen | 328
no to si uz budes musiet nastavit ze ak sa zmeni filter tak resetnes (nastavis na prvu stranu) paginator
- lunak83
- Člen | 47
Chtěl jsem přenášet filtry a pořadí pro řazení mezi stránkami,
takže jsem v presenteru udělal persistentní $filters a $order. Když ale pak
v callbacku zavolám $this->filters = $filters;
tak mám pocit
že se nestane nic, protože odkazy paginatoru se po zadání filtrů vůbec
nemění.
- secmi
- Člen | 19
Ahoj,
pokouším se pomocí kontejneru přidat do filtru dvě pole, minimální a
maximální datum.
Definice filtru je následující:
$grid->setFilterFormFactory(function() {
$form = new Nette\Forms\Container;
...
$form->addContainer('end');
$form['end']->addDatePicker('min');
$form['end']->addDatePicker('max');
...
return $form;
});
ale pokud se pokusím datagrid vypsat, dostanu následující chybu
Call to undefined method Nette\Forms\Container::getControl().
<?php if (isset($_form[$column->name])): $_input = (is_object($column->name) ? $column->name : $_form[$column->name]); echo $_input->getControl()->addAttributes(array()) ;endif ?>
Dělám něco špatně, nebo jde o chybu v datagridu?
Verze Nette 2.0.8
- hrach
- Člen | 1838
Hm, to je proto, ze pouzivam formularova makra z nette, ktery neumi castecny automaticky rendering :| Premyslim jak to resit. Samozrejme bych mohl jednou checknout na Container a proiterovat to, na druhou stranu to neni univerzalni reseni a to se mi nelibi (zanoreni muze byt vice). Otazka je pak, ale ja to jinak resit. Bug je to nekde na pomezi :D
- buffus
- Člen | 101
Díky za parádní datagrid. Mohl bych poprosit o malý příklad, co doplnit do kódu
public function saveData($data)
{
$this->flashMessage('Saving data: ' . json_encode($data->getValues()));
$this->invalidateControl('flashes');
}
aby se po zavolání metody zapsala data z editovaného pole formuláře do databáze?
Editoval buffus (5. 3. 2013 23:15)
- buffus
- Člen | 101
Díky za rady, ale já se špatně zeptal. Mám rozchozené Basic demo a po kliknutí na Edit->Save mi
Firebug Post hlásí OK např.:
Parameters application/x-www-form-urlencoded
edit[firstname] Martha
edit[id] 77
edit[save] Save
edit[surname] Yohannes
...
ale $data zůstává NULL a neumím ji naplnit. Formulář mám jako v demo BasicPresenter.php.
Editoval buffus (6. 3. 2013 10:01)
- buffus
- Člen | 101
<?php
use Nette\Application\UI\Form;
class ZakazkaPresenter extends BasePresenter
{
/** @var Nette\Database\Connection */
private $connection;
public function injectConnection(Nette\Database\Connection $connection)
{
$this->connection = $connection;
}
protected function startup()
{
parent::startup();
if (!$this->getUser()->isLoggedIn()) {
$this->redirect('Sign:in');
}
}
public function createComponentDatagrid()
{
$grid = new Nextras\Datagrid\Datagrid;
$grid->addColumn('id');
$grid->addColumn('zakazkanazevdilu')->enableSort();
$grid->addColumn('neco')->enableSort();
$grid->addColumn('virtual-neco', 'Operace');
$grid->setDataSourceCallback($this->getData);
$grid->setFilterFormFactory(function() {
$form = new Nette\Forms\Container;
$form->addText('zakazkanazevdilu');
$form->addSelect('neco', NULL, array(
'male' => 'železo',
'female' => 'dřevo',
))->setPrompt('---');
return $form;
});
$grid->setEditFormFactory(function($row) {
$form = new Nette\Forms\Container;
$form->addText('zakazkanazevdilu');
!$row ?: $form->setDefaults($row);
return $form;
});
$grid->setEditFormCallback($this->saveData);
$grid->addCellsTemplate(__DIR__ . '/../../libs/Nextras/datagrid/bootstrap-style/@bootstrap3.datagrid.latte');
$grid->addCellsTemplate(__DIR__ . '/../../libs/Nextras/datagrid/bootstrap-style/@cells.latte');
return $grid;
}
public function getData($filter, $order)
{
$filters = array();
foreach ($filter as $k => $v) {
if ($k === 'neco')
$filters[$k] = $v;
else
$filters[$k. ' LIKE ?'] = "%$v%";
}
$selection = $this->connection->table('zakazka')->where($filters);
if ($order) {
$selection->order(implode(' ', $order));
}
return $selection->limit(30);
}
public function saveData($data)
{
$this->flashMessage('Saving data: ' . json_encode($data->getValues()));
$this->invalidateControl('flashes');
}
public function renderDefault()
{
}
}
- buffus
- Člen | 101
Na Basic demo také nejde nic změnit. Předpokládám, že to tak je v online demu schválně. O to naplnění $data by se měl postarat datagrid tak jak to mám v prezenteru sám?
Pokud např. doplním do
public function saveData($data)
{
$datatest = array ("zakazkanazevdilu" => 'ddd', "uzivatelzavedl_id" => '2', "uzivatelzadal_id" => '3');
$this->connection->table('zakazka')->insert($datatest);
$this->flashMessage('Saving data: ' . json_encode($data->getValues()));
$this->invalidateControl('flashes');
}
tak se mi do db po kliknutí na Save normálně řádek přidává…
Editoval buffus (6. 3. 2013 11:32)
- buffus
- Člen | 101
jj, jsem začátečník… Pokud saveData upravím na
public function saveData($data)
{
$this->connection->table('zakazka')->where('id', $data->id)->update($data);
$this->flashMessage('Saving data: ' . json_encode($data->getValues()));
$this->invalidateControl('flashes');
}
tak se v db nic nezmění a Firebug Lite v Chrome vyhodí
POST /…/is/zakazka/?do=datagrid-form-submit 500 Internal Server
Error 88ms
Parametersapplication/x-www-form-urlencoded
edit[id] 3
edit[save] Save
edit[zakazkanazevdilu] chtelBychZmenit-nejde
filter[neco]
filter[zakazkanazevdilu]
a když si dumpnu $data má hodnotu NULL…
Přitom např. Short nebo Filter mi v datagridu funguje, tak snad jsem doplněk nějak blbě nenainstaloval…
Editoval buffus (6. 3. 2013 12:34)