TwiGrid – omlouvám se :-(
- Semik
- Backer | 135
Možná by stačila nějaká do očí bijící výchozí hodnota bloku, takže to poznám, když ho nepřepíšu.
uestla napsal(a):
Rozumím… Tohle je ale celkem špatně uchopitelné – to, jestli blok existuje, pohodlně zjistím v šabloně. Ale vyhazovat výjimku v šabloně mi přijde stejně tak nešťastné… Zkusím něco vymyslet, díky za připomínku.
- Semik
- Backer | 135
Myslel jsem spíš něco jako přidat v kódu sloupci css třídu, aby se dalo aplikovat třeba bootstrap stylování spanX.
Edit: Myslím že stylování v poděděné šabloně gridu bude dostačující. Nechal bych tedy být.
Edit 2: I když v situaci, kdy nepřepisuji bloky s filtry je to celkem
práce navíc, než kdyby se ta třída přidala do
TwiGrid\Components\Column
.
uestla napsal(a):
ad šířka: Šířku si můžeš nastavit podle svého, každá buňka záhlaví má třídu
header-cell-$name
.
Editoval Semik (10. 6. 2013 18:52)
- na1k
- Člen | 288
Dovolím si lehké OT
Nemohl by prosím některý mod tohle vlákno přejmenovat? :-)
Asi jsem přecitlivělý a nechápu srandu, ale vždycky když na mě v nepřečtených příspěvcích vyskočí TwiGrid – omlouvám se :-( tak to vypadá strašně divně. Navíc to ani nevypadá jako hlavní vlákno komponenty, ale o nějaký nováčkovský dotaz.
- boob
- Člen | 21
zdravim,
je mozne nejako vybrat row action na zaklade riadku?
mam napriklad tabulku s riadkami, ktore mozem blokovat, teda pri kazdom riadku
chcem na zaciatku „block“ akciu, ale ked je nieco zablokovane, tak by som
tam chcel mat samozrejme „unblock“ link, najlepsie aj s inym callbackom
da sa to? :)
dakujem
- uestla
- Backer | 799
Akci si dám obecně jako toggle
:
$grid->addRowAction('toggleBlock', '', function ($id) {
// get by $id, unblock if blocked, otherwise block
});
V šabloně pak už jde jen o label:
{define row-action-toggleBlock}
<a href="{$link}" class="btn, btn-info, btn-small, tw-ajax">
{$record->blocked ? 'Odblokovat' : 'Zablokovat'}
</a>
{/define}
- boob
- Člen | 21
Takto som to chcel povodne spravit, ale najradsej by som mal oddelene callbacky pre block a unblock, pretoze takto mi to callbacku pride len id_number a ja neviem, ci je zablokovane alebo nie.
Mozem sa nejako dostat k hodnotam toho riadku?
Pretoze ak si ten grid ulozim do premennej a potom dam napriklad
$this->grid->getData()
, tak mi to refreshne stranku (asi tam
nic nie je a snazi sa tie data nacitat)
Ak mam len id_number, tak by som predtym este musel urobit dalsi request na server, ktory by mi vratil, ci je cislo s takym id blocked alebo unblocked
EDIT // hm, mozem si vlastne tie riadky ulozit do premennej v DataLoader
callbacku
EDIT2 // tak asi nie, lebo DataLoader sa vola az po vykonani
inlineEditCallbacku
Editoval boob (28. 6. 2013 13:36)
- uestla
- Backer | 799
Koukni na to z obou pohledů – jak AJAXového, tak neAJAXového požadavku
Základní fakta:
- všechno je lazy a při zpracování row-action signálu ještě nejsou načtena data (nejsou třeba)
- nemohu vědět, co row-action se záznamem dělá (jestli ho třeba nemaže)
- je proto nutné po zprac. signálu přesměrovat/znovu načíst data
neAJAX
- vyřídí se signál (data nenačtena)
- přesměruje se na sebe sama
- tím dojde k překreslení gridu a zobrazení aktuálních dat
- 2 dotazy do databáze
AJAX
- vyřídí se signál (data nenačtena)
- nepřesměrovává se, ale „invalidují“ se data (tj. řekne se, že se mají znovunačíst)
- jelikož v té době ještě nejsou načtena, nic se neděje
- v první chvíli, kdy jsou data potřeba, se načtou
- a jsou aktuální díky tomu, že row-action signál se zpracuje dřív
- 2 dotazy do databáze
V obou případech stejný počet dotazů (1 na vytažení záznamu podle ID v row-action callbacku, druhý pro získání všech dat aktuální obrazovky).
win-win situation :-)
- boob
- Člen | 21
Jasne, dik, nieco na tom bude :)) je pravda, ze by bolo zbytocne nacitac znova vsetky data, aj ked by to mozno ponuklo zase ine moznosti (napriklad tu by som usetril tu query na ziskanie zaznamu podla ID)
Nedalo by sa tomu callbacku predat nejaky parameter? Teda pri definovani blocku v sablone by som dal href=„{$link} block“ a href=„{$link} unblock“ podla $record->block a podla toho parametru potom vykonal to, co potrebujem v callbacku
- uestla
- Backer | 799
Teoreticky můžeš přidat obě akce a až v šabloně se rozhodnout,
kterou vykreslit (právě v závislosti na
$record->blocked
).
S tím ušetřeným dotazem jsem doufal, že jsem to vysvětlil, ale evidentně ne :-D
Kdybych tahal už při zpracování signálu row-action všechna data kvůli jednomu záznamu, pak bych stejně musel zbytek dat zahodit a načíst celá data znovu, protože nemůžu vědět, co v row-action se záznamem děláš (jestli ho náhodou nemažeš, což by dělalo neplechu při stránkování apod.).
- uestla
- Backer | 799
Ohledně příkladu třeba takhle:
$grid->addRowAction('block', 'Zablokovat', function ($id) { /* ... */ });
$grid->addRowAction('unblock', 'Odblokovat', function ($id) { /* ... */ });
A až pak v šabloně:
{define row-action-block}
<a href="{$link}" class="btn, btn-info, btn-small, tw-ajax" n:if="!$record->blocked">
{$action->label}
</a>
{/define}
{define row-action-unblock}
<a href="{$link}" class="btn, btn-info, btn-small, tw-ajax" n:if="$record->blocked">
{$action->label}
</a>
{/define}
- boob
- Člen | 21
Vdaka, toto vyzera schopne, asi to vyriesim takto :)
S tymi dotazmi mi to je jasne, ja som to myslel tak, ze by som usetril v mojom
pripade 1 dotaz, pretoze teraz by som to robil takto (ak neberiem do uvahy tvoj
posledny navrh):
- zisti podla id, ci je cislo zablokovane alebo nie
- podl toho ho bud odblokuj, alebo zabloku
- nacitaj vsetky data a vykresli
by som mal len 2. a 3. dotaz, kedze 1. by som nepotreboval, keby som hned vedel, ci mam zablokovat alebo nie.. ale zase by som tam musel mat dotaz na ziskanie dat pred callbackom, takze by som nakoniec nic neusetril :)
Dakujem, spravim to teda tymto sposobom, dufam, ze to nebude velmi neprehladne pro viacerych takychto toggle buttonoch :)
- boob
- Člen | 21
zdravim, mal by som po dlhsom case este jednu otazku.
Ked mam komponentu, v ktorej vytvaram grid, teda
<?php
class MyControl
{
public function createComponentMyGrid()
{
$grid = new \TwiGrid\DataGrid($this->context->session);
...
}
public function handleDoSomething()
{
...
}
}
?>
a potreboval by som v stlpci cez custom
{define body-cell-mycolumn}
vykreslit link na handleDoSomething,
teda napriklad
{define body-cell-mycolumn}
<td>
{$value} <a href="...">do something</a>
</td>
{/define}
da sa toto nejako momentalne docielit?
Dakujem!
- ludek
- Člen | 83
Zdravím, díky moc za tenhle grid!
Měl jsem trochu co dělat s původním datagridem Romana Sklenáře a
s NiftyGridem a tenhle se mi zdá jednoznačně nejlepší. Výborně funguje,
výborně vypadá, je připraven pro Nette 2.1. Moc se mi líbí, že např.
obsluhu filtrů (v příkladu metoda filterData()
) si můžu
napsat přesně podle potřeby. Další skvělá věc je nastavení
formátování polí v přidružené .latte šabloně. Myslím, že je škoda,
že není na addons.nette.org. Narazil jsem na něj jen náhodou na fóru.
Programuju jen občas, nemám moc zkušeností, takže mi dost trvalo, než jsem se v příkladu, který se dost liší od normálního Nette sandboxu, trochu vyznal, ale nakonec se mi podařilo přizpůsobit ho pro svůj projekt.
Dotazy:
- Je možné ho nějakým způsobem počeštit, aniž bych zasahoval do kódu?
- Vím, že je to offtopic, ale nedaří se mi pořádně zprovoznit ajax. Myslím, že mám správně načtené všechny js skripty, ale když přepnu třeba filtr v roletovém menu, nic se nestane. Když potom kliknu na tlačítko „Filter“, nejdřív se mi zobrazí alert s hlášením „ahoj“ (? pochází z nette.forms.js) a teprve potom se filtr aplikuje. Kalendáříky datetime pickeru mi také nefungují. I po dlouhém zkoušení pořád nevím, co dělám špatně.
Díky za každou pomoc.
- uestla
- Backer | 799
@ludek:
- ad počeštění:
- můžeš využít překladač
$grid->setTranslator($translator)
a jednotlivé popisky přeložit…
- můžeš využít překladač
- ad AJAX:
- v nette.forms.js jsem žádný podobný alert nenašel, nemáš nějakou starou verzi? Popřípadě vypisuje něco chybová konzole?
@greeny: tohle je vlastnost gridu, kterou považuju za příjemnou, ale chápu, že nemusí vyhovovat všem…
- ludek
- Člen | 83
uestla napsal(a):
- ad AJAX:
- v nette.forms.js jsem žádný podobný alert nenašel, nemáš nějakou starou verzi? Popřípadě vypisuje něco chybová konzole?
Díky. Bylo to tím, že jsem neměl natažený
highlight.pack.js
, protože jsem se domníval, že ho nepotřebuju.
Ve script.js
se ale hned na začátku volá
hljs.initHighlightingOnLoad();
, což způsobilo, že pak
nefungovalo nic. Stačilo zakomentovat.
Jinak v nette.forms.js
, který je součástí Vašeho příkladu
je to na řádku 137:
Nette.validateForm = function(sender) {
var form = sender.form || sender, scope = false;
alert('ahoj');
V NetteFramework-2.1.1/client-side/netteForms.js
to není.
Editoval ludek (6. 3. 2014 13:48)
- ludek
- Člen | 83
Jak udělat klikatelný text (odkaz) v buňce?.
Chtěl bych udělat toto:
{define body-cell-name}
<td><a n:href="Dashboard:detail $id">{$value}</a></td>
{/define}
Ale jednak obdržím chybu
„Component with name 'Dashboard' does not exist
“, a také
nevím jak se dostat k hodnotě $id
aktivního řádku.
- tom
- Člen | 171
uestla napsal(a):
To vypadá buď na špatně nastavený data loader nebo value getter, mohl bys ukázat kód definice gridu?
Zkoušel jsem to takto …
<?php
$grid = new \TwiGrid\DataGrid($this->context->session);
$grid->setPrimaryKey('id_role');
$grid->addColumn('name', 'Name');
$grid->setDataLoader($this->cRolesRepository->vratDataSource());
return $grid;
?>
- zapp
- Člen | 32
Ahoj,
bohužel se mi nedaří zprovoznit řazení, ani filtrování. Pokud nepoužiju
ajax, vše funguje, jinak při překreslení laděnka píše, že nezná
proměnnou „form“. Může mě někdo nakoupnout prosím?
default.latte – volá componentu
{block content}
<p>
<a href="{plink Contracts:add}" class="btn btn-primary">Přidat zakázku</a>
</p>
{control contracts}
ContractsPresenter.php – výtažek
class ContractsPresenter extends BasePresenter {
public $contracts;
public function actionDefault () {
$this->contracts = $this->model->getContracts();
}
public function createComponentContracts () {
return $this->context->createService('contractsGrid');
}
}
ContractsGrid.php
class ContractsGrid extends DataGrid {
/** @var \Model @inject */
public $model;
protected function build () {
$this->setTemplateFile(APP_DIR . '/templates/Grid/contracts.latte');
$this->setPrimaryKey('id');
$this->addColumn('no', 'Číslo')->setSortable();
$this->addColumn('name', 'Název')->setSortable();
$this->addColumn('companies_id', 'Firma')->setSortable();
$this->addColumn('delivery_date', 'Termín objednání')->setSortable();
$this->addColumn('text', 'Popis');
$this->addRowAction('edit', 'Upravit', $this->edit);
$this->addRowAction('delete', 'Smazat', $this->delete)
->setConfirmation('Opravdu smazat?');
$this->setDefaultOrderBy('delivery_date', 'ASC');
$this->setFilterFactory($this->filterFactory);
$this->setDataLoader($this->dataLoader);
}
public function dataLoader ($grid, array $columns, array $filters, array $order) {
$contracts = $this->model->getContracts();
// sorting
foreach ($order as $column => $direction) {
$contracts->order($column . ($direction === Column::DESC ? ' DESC' : ''));
}
// filtering
foreach ($filters as $column => $value) {
if ($column == 'companies_id') {
$companies = $this->model->getCompanies()->where('name LIKE ?', '%'.$value.'%')->fetchPairs('id', 'id');
$contracts->where('companies_id', array_values($companies));
}
else {
$contracts->where($column.' LIKE ?', '%'.$value.'%');
}
}
return $contracts;
}
public function filterFactory () {
$container = new Container;
$container->addText('no');
$container->addText('name');
$container->addText('companies_id');
return $container;
}
public function edit ($id) {
$this->presenter->redirect('Contracts:edit');
}
public function delete ($id) {
}
}
- jarks
- Člen | 94
Dobrý den, velmi pěkný grid – alespoň demo vypadá skvěle. Také
velmi pěkný návod na zprovoznění. Když ho ale projdu a za bodem 8 chci
spustit výsledek, dostanu chybu
„headers already sent
“ a bohužel se mi
nedaří zjistit proč. Nebylo by prosím úplně celé kompletní demo včetně
použité Nette atd. ke stažení, že bych ho zkusil rozběhnout na lokálu a
snažil se najít v čem to je?
Nette\InvalidStateException
session_start(): Cannot send session cache limiter - headers already sent (output started at C:\web\www\twigrid-quickstart\temp\cache\latte\www-twigrid-quickstart-app-templates-layout-latte-7cfc6ddb213bd27e9582d09c56d86154.php:57)
//---------------------------------
...\vendor\uestla\twigrid\src\TwiGrid\Helpers.php:144
144: ? static::getCsrfTokenSession($session, $namespace)->token = NRandom::generate(10)
Arguments
$name "token" (5)
$value "xwle1qftzq" (10)
//-----------
...\temp\cache\latte\www-twigrid-quickstart-app-templates-layout-latte-7cfc6ddb213bd27e9582d09c56d86154.php:79
79: <?php Latte\Macros\BlockMacros::callBlock($_b, 'content', $template->getParameters()) ?>
- jarks
- Člen | 94
Pomohlo, díky. To mě taky mohlo napadnout. Zjistil, že se to projevuje ve Firefoxu. V Chrome ne.
A ještě: pokud se postupuje jen podle tutorialu, nefunguje ajax, protože chybí inicializace
$(function () {
$.nette.init();
});
což je v demu v souboru script.js
. Dá se vyřešit
připsáním do main.js
(který je v sandboxu prázdný) jak je
popsáno v Simple Ajax
Example a nalinkováním v @layout.latte
, pokud už to
tam není:
<script src="{$basePath}/js/main.js"></script>
Editoval jarks (5. 9. 2014 16:25)
- jarks
- Člen | 94
Třeba se bude hodit začátečníkům:
instalace TwiGrid DEMO na lokální webserver:
předpoklad: nainstalovaný composer
postup:
- https://github.com/…twigrid-demo
- [Download ZIP] (https://github.com/…e/master.zip)
- rozbalit např. do ~/www/twigrid-demo nebo C:\www\twigrid-demo
- přejít do adresáře s rozbaleným TwiGridem
- otevřít konzolu (ve Windows CMD), zadat:
composer update
– přiinstaluje se Nette - Linux: nastavit práva k adresářům
temp
,log
(chmod -R 777 log/ temp/
) a jestli nechcete chybové hlášky, tak ještě kjs
acss
, kam se pokouší při spuštění zapisovat - v prohlížeči zadat adresu např. http://localhost/twigrid-demo
Editoval jarks (30. 3. 2015 12:53)
- ludek
- Člen | 83
Jestli při vícenásobném otevření okna (prostřední tlačítko) se
řádkovou akcí dostanete
"Security token does not match. Please try again."
a nechcete to
tak, je třeba doplnit vypnutí ochrany proti CSRF, takto:
protected function build()
{
//...
$this->addRowAction('edit', 'Upravit', $this->editItem)
->setProtected(FALSE); //<< tady to je
//...
}
function editItem(Nette\Database\Table\ActiveRow $record) {
$this->getPresenter()->redirect("Homepage:edit", $record->id);
}
Editoval ludek (14. 10. 2014 16:42)
- amik
- Člen | 118
Podle mě nejlepší datagrid pro Nette, hlavně mě fascinuje napojení na model přes callbacky. Od gridu čekám maximální customizovatelnost, což twigrid nepochybně má :) pár věcí mi ještě v jeho jádru chybělo, mám je zatím dobastlené u sebe na projektu, ale chystám se udělat si fork a rozumně to rozházet do commitů, a případně hodit pull request když se to bude líbit :)