Nextras\Datagrid – datagrid se vsim jak ma byt
- MW
- Člen | 626
Prosím o radu:
možná na to jdu špatně.
Dělám si podporu pro tisk. V šabloně print.latte kde mam do samé co
například v default.latte +
{extends none}
A v gridu jsem si udělal link
{define global-actions}
<a href="{plink print}" target="_blank">Tisk</a>
{/define}
A v presenteru
function handlePrint() {
$this->presenter->setView('print');
}
Což samozřejmě zobrazí grid v default stavu. Lze nějak chytře předat stav? (filtry, page a pod?)
Nebo jak chytře řesit tisk, prosim ?
Diky !
Editoval MW (10. 7. 2013 17:23)
- Vojtěch Dobeš
- Gold Partner | 1316
Nejsnazší cestou bude, jak zmínil jiri.pudil, vytvořit tiskový stylopis. Pak nemusíš mít pro tisk separátní šablonu, uživatel prostě v prohlížeči dá Tisk (lze mu na to udělat i tlačítko javascriptem) a stránka se vytiskne v upravené podobě tak, jak řeknem v CSS. Ideální způsob vytvoření tiskového stylopisu je pomocí media queries v hlavním stylopisu, aby se kvůli němu nedělal zbytečný HTTP request navíc (prohlížeče tiskový stylopis stáhnou, i když uživatel tisknout nechce).
@media print {
aside, #header, #footer {
display: none;
}
}
<a href="#" onclick="window.print();return false;">Tisk</a>
Dobrý užitečný základ pro tiskový stylopis lze najít v HTML5 Boilerplatu.
Editoval vojtech.dobes (11. 7. 2013 0:26)
- MW
- Člen | 626
Nějak jsem to udělal, ale nepřijde mě, že nějak pěkně a tak prosím o nějaký komentář:
presenter:
/** @persistent */
public $pag = 10;
a továrně pak:
public function createComponentUsers() {
$grid = new \Nextras\Datagrid\Datagrid;
.....
$grid->setPagination($this->pag, $this->getDataSourceSum);
...
}
public function handlePag($show) {
$this->pag = $show;
$this->invalidateControl('grid');
}
do šablony zkušebně pak:
<br />
Zobrazit:
<a href="{plink pag!, 'show' => 1}" class="ajax">1</a>
<a href="{plink pag!, 'show' => 5}" class="ajax">5</a>
<a href="{plink pag!, 'show' => 10}" class="ajax">10</a>
na stránku.
Díky !
- mrtnzlml
- Člen | 140
Ahoj. Nahrazuji datagridem původní šablony, kde se vše renderovalo ručně. Snažím se to udělat tak, aby byl výsledek úplně stejný (a díky datagridu lepší). Lze nějak nadefinovat (třeba v šabloně pomocí addCellsTemplate) co bude grid vykreslovat, když je prázdný? Takto se vykresluje normálně tabulka bez dat a musím do šablony (podle mě zbytečně) ještě tahat informaci o tom, že žádná data neexistují. Bylo by docela cool, kdyby v případě prázdných dat byl třeba místo formuláře <p> a v něm nějaká hláška…
- hrach
- Člen | 1838
@mrtnzlml: no, pokud jde o samotnou tabulku (tedy hlavicku, etc), tak nemam v planu zavadet nejakou monost, ze by se nevykreslila. Pokud jde o to, ze by byl treba vykreslen samotny radek s jednou dlouho bunkou, ze data najsou, tak to je v planu (aby to bylo taky modifikovatelne).
- mrtnzlml
- Člen | 140
Hm, to je škoda. Zeptám se tedy jaký je nejlepší způsob jak to řešit?
{if !empty($xxx)}
{control xxxDatagrid}
{else}
<p>xxx je prázdné ... <a>vytvořit nové xxx</a></p>
{/if}
Takto to řeším teď a vzešlo to z původního řešení, kdy se nepoužíval datagrid. Ale teď se mi to nelíbí, abych se v každém callbacku ptal znovu na data a ještě si to posílal do šablony. Zvlášť když jsou data z externího zdroje, kdy nelze uplatnit limit (a jsou ve formátu array())…
- buffus
- Člen | 101
Používám Nette 2.0.11, Nextras/Datagrid, jQuery v1.9.1, nette.ajax.js
v1.2.2 a i kód z ukázky v dokumentaci
Possible NAIVE implementation for Nette\Database could look
like this:
$grid->setDatasourceCallback(function($filter, $order) {
$filters = array();
foreach ($filter as $k => $v) {
if ($k == 'id' || is_array($v))
$filters[$k] = $v;
else
$filters[$k. ' LIKE ?'] = "%$v%";
}
$selection = $this->connection->table('user')->where($filters);
if ($order[0])
$selection->order(implode(' ', $order));
return $selection;
});
Potřeboval bych v Datagridu vypsat výchozí výpis sestupně podle id a zároveň i funkční enableSort.
Pokud zadám
$selection = $this->connection->table('zakazka')->where($filters)->order('id DESC');
nebo do
$order = array('id DESC');
vypíše datagrid sice výpis sestupně podle id, ale přestane u všech
sloupců fungovat enableSort
$grid->addColumn('id', 'UID')->enableSort();
,
který před použitím order
funguje.
Můžete mi prosím někdo pomoci?
- buffus
- Člen | 101
Dotazy jsou:
při $order = array('id DESC');
SELECT `id`, `nazevdilu`, `provozovna_id`, `uzivatelzavedl_id`, `uzivatelzadal_id`,...,
FROM `zakazka`
ORDER BY `id` DESC
LIMIT 30
enableShort nefunguje,
při //$order = array('id DESC');
SELECT `id`, `nazevdilu`, `provozovna_id`, `uzivatelzavedl_id`, `uzivatelzadal_id`,...,
FROM `zakazka`
LIMIT 30
enableShort funguje. Ty dotazy se mi zdají korektní.
- buffus
- Člen | 101
Prosím ještě o radu. Dávám to do vlákna Nextras\Datagridu, protože jsem při jeho používání na můj problém narazil u createComponentDatagrid(), ale jinak tuším, že v mém případě půjde spíše o začátečnický problém s OOP/PHP.
Úryvek kódu:
<?php
use Nette\Application\UI\Form;
class ZakazkaVypisPresenter extends BasePresenter
{
private $connection;
public function injectConnection(Nette\Database\Connection $connection)
{
$this->connection = $connection;
}
public function createComponentDatagrid()
{
$grid = new Nextras\Datagrid\Datagrid;
$grid->addColumn('provozovna_id', 'Provozovna')->enableSort();
$grid->setDataSourceCallback($this->getData);
$grid->setFilterFormFactory(function() {
$form = new Nette\Forms\Container;
$form->addSelect('provozovna_id', NULL, array($this->connection->table('provozovna')->fetchPairs('id', 'mesto')))->setPrompt('-- zvolte --');
return $form;
});
return $grid;
}
}
Pokud v řádce:
$form->addSelect('provozovna_id', NULL, array(
vypíšu pole ručně, např. pokračuji kódem:
array('1' => 'Plzeň', '2' => 'Praha',
filtr funguje (musím filtr takto řešit, pač jde o cizí tabulku a v podstatě filtruji id těch měst).
Ale pokud zadám pole jako dotaz do DB (používám NDB Nette 2.0.11):
array($this->connection->table('provozovna')->fetchPairs('id', 'mesto'))
Laděnka vyhodí:
Fatal Error – Using $this when not in object context
a i Phpstorm $this červeně podtrhne s bublinou:
„$this in Closure is allowed in PHP5.4 only“
Tomu rozumím, ale poradit si neumím. Vyvíjím na PHP5.3 (to můžu změnit), ale na produkci mají teď 5.3 a s tím jen tak nehnu. Server ale nechci na fóru řešit, to se poddá, ale uvítal bych radu, jak to pole naplnit přes fetchPairs dotaz, aby fungoval i teď na pHP5.3. Předem díky.
- buffus
- Člen | 101
@enumag: Díky moc za nasměrování, už to frčí. @hrach: Věř mi, že jsem u mého problému nad novým vláknem přemýšlel… A určitě Ti toto vlákno nechci spamovat. Ale OK, přijímám napomenutí a slibuji, že budu šířit slávu Tvého skvělého Datagridu mými jalovými dotazy i v jiných vláknech a fórech.
- rixi
- Člen | 109
hrach wrote:
bohuzel moc nejde. na co to presne potrebujes? vim, ze je to hloupe, zkusim jeste popremyslet, jak to vyresit.
Z hlavy ma napadlo http://getbootstrap.com/css/#… , pridavanie classov na riadky by som urcite vyuzil.
- enumag
- Člen | 2118
@hrach: V čem je problém? Moje primitivní komponenta na výpis tabulky to umí.
{capture $list}
{#table-open-tag}
<table>
{/#}
<thead>
<tr>
{foreach $control->columns as $column}
<th>{$column->label}</th>
{/foreach}
<th n:if="!empty($control->actions)">Akce</th>
<tr>
</thead>
<tbody>
{foreach $control->entities as $entity}
{#row-open-tag entity => $entity}
<tr>
{/#}
{foreach $control->columns as $column}
{#col-$column->name entity => $entity}
<td>{$entity->{$column->name}}</td>
{/#}
{/foreach}
<td n:if="!empty($control->actions)" n:inner-foreach="$control->actions as $action" class="actions">
{control $action->destination entity => $entity}
</td>
{#row-close-tag entity => $entity}
</tr>
{/#}
{/foreach}
</tbody>
{#table-close-tag}
</table>
{/#}
{/capture}
{if $iterations > 0}
{!$list}
{else}
{#no-items}{/#}
{/if}
- Quinix
- Člen | 108
hrach napsal(a):
bohuzel moc nejde. na co to presne potrebujes? vim, ze je to hloupe, zkusim jeste popremyslet, jak to vyresit.
Chtěli jsme k řádkům přidat „data-href“ a udělat je celé proklikávací na editaci… zatim to mam vyřešené jinak, ale vlastní attr k <tr> by byl nejlepší. Co to udělat stejně jako je definování vlastního otevíracího tagu <table>?
- MW
- Člen | 626
Zdravím a prosím o pomoc.
Mam grid kam bych si rad pripojil podle ID z jiné tabulky NAME.
Rekneme tabulka CARS kde je sloupec branches_id a tabulka BRANCHES, která ma NAME.
Jak to spravne pripojit a zachovat funkcni inline editaci? Bez inline editace to umim přes SELECT() tedy to udela spravny JOIN.
Tedy do gridu pridavam:
$grid->addColumn('branches_id')->enableSort();
v datasource mam
$this->database->table('cars');
a i jsem si udelal v editFormFactory
$form->addSelect('branches_id', 'Provozovna', $_this->context->carsModel->getBranches()->fetchPairs('id', 'name'));
Ale potrebuji mit v gridu NAME a ne Id …
Pokud to zkusim přes JOIN v Datasourcu, nedari se me to udelat spravne..
Dekuji
- vvoody
- Člen | 910
Cell rendering si naštuduj v dokumentácií. A ten addSelect máš správne, tak ako si ho napísal ho pridaj do setEditFormFactory. Podstatné je aby identifikátor inputu bol zhodný s identifikátorom stĺpca, čiže branches_id.
- MW
- Člen | 626
Super!
Takze i když necham jako source
$this->data = $this->database->table('printers');
a zavolam v sablone při rucnim renderu
{$row->branches->name}
vyvola to dotaz
SELECT `id`, `name`
FROM `branches`
WHERE (`id` IN (16, 1))
Coz je super… znamena to tedy, ze musim dodrzet nazvy tabulek/sloupcu,
ze?
Tedy sloupec tabulka_id …
Ted se zeptam blbe, to není věc gridu, ale uz Nette\Database, ze?
Diky !
- MW
- Člen | 626
Takto jsem poresil moznost zadavat počet zobrazenych stranek. Takto to
i funguje..
Ale po tom, co jsem to takto implementoval do existujici aplikace, do casti
prezenteru, me to prestalo fungovat.
Jediny rozdil je v tom, ze presenter ma formular, kde zvolim rok a přes setview() to poslu na sablonu, kde nacitam control s gridem.
Pokud to krokuju, tak po zavolani
$this->invalidateControl('grid');
se me jiz nevvytvari znovu componenta Users..
Když to mam v cistem presenteru, tak to pokazde jde na
$grid = new \Nextras\Datagrid\Datagrid;
Prosim o radu…
Tady je kod:
presenter:
/** @persistent */
public $pag = 10;
a továrně pak:
public function createComponentUsers() {
$grid = new \Nextras\Datagrid\Datagrid;
.....
$grid->setPagination($this->pag, $this->getDataSourceSum);
...
}
public function handlePag($show) {
$this->pag = $show;
$this->invalidateControl('grid');
}
do šablony zkušebně pak:
<br />
Zobrazit:
<a href="{plink pag!, 'show' => 1}" class="ajax">1</a>
<a href="{plink pag!, 'show' => 5}" class="ajax">5</a>
<a href="{plink pag!, 'show' => 10}" class="ajax">10</a>
na stránku.
Editoval MW (22. 8. 2013 13:46)
- enumag
- Člen | 2118
@Milo: Ne že bych to v praxi sám používal, ale udělal bych to tak jak píše @hrach s tím že bych to pomocí absolutního pozicování vytáhl mimo tu buňku aby se zbytečně nenatahovala. V podstatě si to představuju tak že by pod inputem vyjela bublina s chybou. (Hrachův datagrid to tak možná dělá – nepoužívám jej takže to nevím.)
- MW
- Člen | 626
Zdravím, a prosím o pomoc.. zasekl jsem se :/
V presenteru mám formulář se zadáním roku a po odeslani nastavim view na sablonu s komponentou gridu.
Ja potrebuji nekam podstrcit parametr $year do metody getData v modelu a pridat ji do selectu.
Jak na to prosim?
EDIT:
sice se v modelu dostanu na $_POST[‚year‘], ale to asi není spravne reseni
…
volani
$this->context->invoicesModel->getDataSource
se me nedari rozsirit o napr getDataSource($this->year) .. nebo nevim jak na to
v presenteru mám komponentu:
public function createComponentHistory() {
$grid = new \Nextras\Datagrid\Datagrid ();
$grid->addColumn('id');
$grid->addColumn('name')->enableSort();
$grid->addColumn('branches_id', 'Provozovna')->enableSort();
$grid->addColumn('leden', 'Leden');
$grid->addColumn('unor', 'Únor');
$grid->setDatasourceCallback($this->context->invoicesModel->getDataSource);
$grid->setPagination($this->pag, $this->context->invoicesModel->getDataSourceSum);
$this_ = $this;
$grid->setFilterFormFactory(function() use ($this_) {
$form = new Nette\Forms\Container;
$form->addText('name');
$form->addSelect('branches_id', 'Provozovna', $this_->context->printersModel->getBranches()->fetchPairs('id', 'name'))->setPrompt('Zvolte');
$form->addSubmit('filter', 'Filtrovat')->getControlPrototype()->class = 'btn btn-primary';
$form->addSubmit('cancel', 'Zrušit filtr')->getControlPrototype()->class = 'btn';
return $form;
});
$grid->addCellsTemplate(LIBS_DIR . '/Addons/Nextras-datagrid/Lattes/history.latte');
return $grid;
}
zde mam také persistentni parametr $year
/** @persistent */
public $year;
a model pak podle vzoru:
public function getData() {
return $this->database->table('contracts')->SELECT('id, name, branches_id,
(SELECT SUM(sum) FROM mrp WHERE MONTH(datzdanpln) = 1 AND YEAR(datzdanpln) = 2013 AND mrp_cislo = cislo_zak) AS leden,
(SELECT SUM(sum) FROM mrp WHERE MONTH(datzdanpln) = 2 AND YEAR(datzdanpln) = 2013 AND mrp_cislo = cislo_zak) AS unor
');
}
public function prepareDataSource($filter, $order) {
$filters = array();
foreach ($filter as $k => $v) {
if ($k == 'id' || is_array($v))
$filters[$k] = $v;
else
$filters[$k . ' LIKE ?'] = "%$v%";
}
$selection = $this->getData()->where($filters);
if ($order[0])
$selection->order(implode(' ', $order));
return $selection;
}
public function getDataSource($filter, $order, Paginator $paginator = NULL) {
$selection = $this->prepareDataSource($filter, $order);
if ($paginator) {
$selection->limit($paginator->getItemsPerPage(), $paginator->getOffset());
}
return $selection;
}
public function getDataSourceSum($filter, $order) {
return $this->prepareDataSource($filter, $order)->count('*');
}
Editoval MW (27. 8. 2013 18:38)
- Milo
- Nette Core | 1283
Pardon, chybělo mi tam return. Opravil jsem.
setDatasourceCallback()
chce jako parametr callback (něco, co
může zavolat). Volání
$this->context->invoicesModel->getDataSource($this->year)
vrací data, takže předáváš data.
Předpokládám, že InvocesModel dědí od Nette\Object. Proto Ti funguje
$this->context->invoicesModel->getDataSource
. Kdyby
nedědil, tak getDataSource
je nedefinovaná proměná.
Nette\Object se podívá, jestli existuje metoda getDataSource
a
namísto chyby o nedefinované proměnné vrátí callback na tu metodu.
- MW
- Člen | 626
Super! diky…
$year jsem tam konecne dostal a funguje …
Az na paginator.. zas asi delam něco blbe :/
Moc prosim ještě o pomoc..
Vypada to ze getDataSource vůbec Paginator nedostane..
EDIT: Paginator se přitom vykresli, i sedi počet stranek,
jaky by mel byt, filtr funguje, jen proste zobrazi vse :/
a v podmínce
if ($paginator) {
$selection->limit($paginator->getItemsPerPage(), $paginator->getOffset());
}
je $paginator NULL :/
Diky !
Presenter:
public function createComponentHistory() {
$grid = new \Nextras\Datagrid\Datagrid ();
$grid->addColumn('id');
$grid->addColumn('name')->enableSort();
$grid->addColumn('branches_id', 'Provozovna')->enableSort();
$grid->addColumn('leden', 'Leden');
$grid->addColumn('unor', 'Únor');
...
$_this = $this;
$grid->setDatasourceCallback(function($filter, $order) use ($_this) {
return $_this->context->invoicesModel->getDataSource($filter, $order, $_this->year);
});
$grid->setPagination($_this->pag, function($filter, $order) use ($_this) {
return $_this->context->invoicesModel->getDataSourceSum($filter, $order, $_this->year);
});
$grid->setFilterFormFactory(function() use ($_this) {
$form = new Nette\Forms\Container;
$form->addText('name');
$form->addSelect('branches_id', 'Provozovna', $_this->context->printersModel->getBranches()->fetchPairs('id', 'name'))->setPrompt('Zvolte');
$form->addSubmit('filter', 'Filtrovat')->getControlPrototype()->class = 'btn btn-primary';
$form->addSubmit('cancel', 'Zrušit filtr')->getControlPrototype()->class = 'btn';
return $form;
});
$grid->addCellsTemplate(LIBS_DIR . '/Addons/Nextras-datagrid/Lattes/history.latte');
return $grid;
}
a model:
public function getData($year) {
return $this->database->table('contracts')->SELECT('id, name, branches_id,
(SELECT SUM(sum) FROM mrp WHERE MONTH(datzdanpln) = 1 AND YEAR(datzdanpln) = '.$year.' AND mrp_cislo = cislo_zak) AS leden,
(SELECT SUM(sum) FROM mrp WHERE MONTH(datzdanpln) = 2 AND YEAR(datzdanpln) = '.$year.' AND mrp_cislo = cislo_zak) AS unor, ....
');
}
public function prepareDataSource($filter, $order, $year) {
$filters = array();
foreach ($filter as $k => $v) {
if ($k == 'id' || is_array($v))
$filters[$k] = $v;
else
$filters[$k . ' LIKE ?'] = "%$v%";
}
$selection = $this->getData($year)->where($filters);
if ($order[0])
$selection->order(implode(' ', $order));
return $selection;
}
public function getDataSource($filter, $order, $year, Paginator $paginator = NULL) {
$selection = $this->prepareDataSource($filter, $order, $year);
if ($paginator) {
$selection->limit($paginator->getItemsPerPage(), $paginator->getOffset());
}
return $selection;
}
public function getDataSourceSum($filter, $order, $year) {
return $this->prepareDataSource($filter, $order, $year)->count('*');
}
Editoval MW (28. 8. 2013 11:38)
- Filip111
- Člen | 244
@hrach:
Ahoj, předně díky za perfektní grid – nahradil jsem tím spoustu starých
tabulkových výpisů a vše šlape jak má. Po víc jak půl roce používání
můžu jedině doporučit.
Co se mi nejvíc líbí, jsou bloky pro každý sloupec definované
v šabloně. Můžu se tam vyblbnout jak potřebuju. Dál je pro mě naprosto
super vlastností libovolný formát vypisovaných dat – je jedno jestli je
řádek pole, vlastní class, entita Doctrine, LeanMapperu…vše mám
vyzkoušené.
K otázce: stále plánuješ, případně kdy přidání
podpory pro víceřádkové akce?
V issues na githubu i v diskuzi už to zaznělo, ale jen jednou a před
docela dlouhou dobou.
Díky.
- jiri.pudil
- Nette Blogger | 1029
Vypada to ze getDataSource vůbec Paginator nedostane..
Když si ho tam nepředáš, nediv se, že tam není.
return $_this->context->invoicesModel->getDataSource($filter, $order, $_this->year/* tady něco chybí */);