Yii 1.1: edatatables

DataTables grid widget with CGridView API.
43 followers

Goal of this widget/wrapper is to provide a drop in replacement for base CGridView widget from the Yii framework, using DataTables plugin.

It's usable, but feedback is needed. Please post issues on project's page.

Features

  • Redrawing of table contents (after paging/sorting/searching) using AJAX calls.
  • Using CGridView columns definition format, supports all basic special columns like Buttons, Checkbox, etc.
  • Custom buttons in table header.
  • Smoothness theme from JUI by default
  • Twitter Bootstrap support through the bootstrap extension
  • Partial editable cells support.

Requirements

Changes

0.9.2

  • re-enabled beforeAjaxUpdate option
  • disabled default configure button, as this requires the select2 extension

0.9.1

  • removed fixed width on first column if selectableRows != 0
  • allow passing null to buttons option to disable all default buttons
  • fix default JS action on delete button in EButtonColumn
  • register select2 JS plugin from ESelect2 extension if configure button is enabled
  • removed all the JS code for drawing active forms in modal dialogs

0.9.0

  • updated DataTables to 1.9.4
  • refactored editable columns and changed the way rows are selected, read more on the wiki
  • refactored and moved all ajax related code from the class file to the js plugin file
  • added refresh and search JS methods to trigger reloading of grid's contents
  • added column names to the dataTables definition, send their order and visibility to the server with every ajax request
  • added a static restoreStateSession method to save and restore pagination, sorting and columns order/visibility in/from session, see the wiki
  • fixed retrieving key values from dataProvider
  • add an implementation of parse_str borrowed from CakePHP framework to restore contents of editable columns
  • changed every occurence of $_REQUEST to $_GET
  • fixed EDTPagination not storing itemCount properly
  • fixed delete button JavaScript callback that should refresh the grid's contents
  • added a definition for a "history" button, that's supposed to open a record modifications log

Usage

It's not 100% compatible with CGridView. I've decided not to alter the GET parameter names used by DataTables, so you have to use the provided EDTSort and EDTPagination classes as well as alter filter processing. See below.

Installation

Extract into extensions dir.

Import in config/main.php

'import' => array(
  ...
  'ext.EDataTables.*',
  ...

Using

Use similar to CGridView. If displayed in a normal call just run the widget. To fetch AJAX response send json encoded result of $widget->getFormattedData().

The action in a controller:

$widget=$this->createWidget('ext.EDataTables.EDataTables', array(
 'id'            => 'products',
 'dataProvider'  => $dataProvider,
 'ajaxUrl'       => $this->createUrl('/products/index'),
 'columns'       => $columns,
));
if (!Yii::app()->getRequest()->getIsAjaxRequest()) {
  $this->render('index', array('widget' => $widget,));
  return;
} else {
  echo json_encode($widget->getFormattedData(intval($_REQUEST['sEcho'])));
  Yii::app()->end();
}

The index view (for non-ajax requests):

<?php $widget->run(); ?>

Preparing the dataprovider

To use features like sorting, pagination and filtering (by quick search field in the toolbar or a custom advanced search filter form) the dataprovider object passed to the widget must be prepared using provided EDTSort and EDTPagination class and CDbCriteria filled after parsing sent forms.

The simplest example:

$criteria = new CDbCriteria;
// bro-tip: $_REQUEST is like $_GET and $_POST combined
if (isset($_REQUEST['sSearch']) && isset($_REQUEST['sSearch']{0})) {
    // use operator ILIKE if using PostgreSQL to get case insensitive search
    $criteria->addSearchCondition('textColumn', $_REQUEST['sSearch'], true, 'AND', 'ILIKE');
}
 
$sort = new EDTSort('ModelClass', $sortableColumnNamesArray);
$sort->defaultOrder = 'id';
$pagination = new EDTPagination();
 
$dataProvider = new CActiveDataProvider('ModelClass', array(
    'criteria'      => $criteria,
    'pagination'    => $pagination,
    'sort'          => $sort,
))

An advanced example would be based on a search form defined with a model and a view. Its attributes would be then put into a critieria and passed to a dataProvider.

Other options

Check out the DataTables web page for docs regarding:

  • Table layout
  • Styling
  • Multi-column sorting etc.
  • Tons of examples and funky plugins

Resources

Total 20 comments

#17577 report it
heal at 2014/07/04 06:14am
ok

I'we wroted down the details in the forum:
http://www.yiiframework.com/forum/index.php/topic/54557-adding-select-dropdown-for-edatatable/page__gopid__254607#entry254607

Is your widget id 'vpds'? - yes
Do you call that JS AFTER initializing the widget? - yes

#17576 report it
nineinchnick at 2014/07/04 06:01am
forum

Please use forum to ask for help. Is your widget id 'vpds'? Do you call that JS AFTER initializing the widget?

#17575 report it
heal at 2014/07/04 05:49am
thanks

Thank you nineinchnick! Can you please tell me, what's wrong now with my code?

var table = $.fn.eDataTables.tables['vpds'];  
    $('#DataTables_Table_0 tfoot td').each( function ( i ) {  
        var select = $('<select><option value=\"\"></option><option value=\"1\">1</option></select>')  
        .appendTo( $(this).empty() )  
        .on( 'change', function () {  
            table.column( i )    // <-- Uncaught TypeError: undefined is not a function 
            .search( $(this).val() )  
            .draw();  
        } );  
    } );
#17574 report it
nineinchnick at 2014/07/04 05:36am
instance

There is no eDataTables instance. You can read the underlying dataTables at $.fn.eDataTables.tables[id] or eDataTables settings at $.fn.eDataTables.settings[id].

#17573 report it
heal at 2014/07/04 05:21am
edatatables object

Hello, how can I get the edatatables object in js? I want to create custom inputs for filtering the table.

My code...

var tablevpds = jQuery('#vpds').eDataTables({'baseUrl':...});
console.log(tablevpds);

..returns 'undefined'

#17055 report it
Chintan Chiku at 2014/04/29 05:15am
weird error

Declaration of EDataColumn::getDataCellContent() should be compatible with CDataColumn::getDataCellContent($row)

#16078 report it
nineinchnick at 2014/01/17 01:04am
changes

Thanks. Please consider posting feature requests on the Github project page as issues. Maybe some of your changes could be more generic and helpful for others. Let's discuss it on Github.

#16077 report it
jcagentzero at 2014/01/17 12:41am
Thanks a lot!!!

We are very happy to thank you for this extension although we have made a lot of changes to your extension. But creating this extension gives us hope nearly 6 months ago.:)

#16060 report it
heal at 2014/01/15 07:54am
Thank you!

I would only say thank you for this extension! GREAT work!

#15369 report it
nineinchnick at 2013/11/02 04:28am
input

Thanks, I invite you to the github project page. Open up some issues and we'll discuss solutions :-)

#15360 report it
FrankW at 2013/11/01 12:08am
Almost rolled my own and found this.

Nice work on this. Although it may need improvement, but dataTables is a complex solution, and I think this is well done. I've added it to a current project and would like to offer input at some point.

#14917 report it
Amini at 2013/09/21 05:43am
TableTools

how to enable print button in TableTools datatable? refresh and configure buttons work very well, but print button not work!

  1. how to work it?
  2. or what is callback function for this?
  3. or how to used from TableTools.js in EdataTable?
#14835 report it
nineinchnick at 2013/09/13 09:36am
demo

Pass it the same column configuration you pass to the widget. It param is commented in the example model.

#14833 report it
Shady at 2013/09/13 09:07am
demo

followed the demo, mh.. sorry, but still not good for me,

Argument 1 passed to Transactions::search() must be an array, none given, called in /var/www/journals/protected/views/transactions/admin.php on line 126 and defined

117 public function search(array $columns)

118 {

#14832 report it
nineinchnick at 2013/09/13 07:41am
demo

I've just created a demo, see the source on github for example how to use it:

#14791 report it
Shady at 2013/09/10 03:12am
Extension

explanation not enough for a beginner to get things running. Didn't work for me

#14484 report it
nineinchnick at 2013/08/16 03:47am
ajax url

Fixed, thanks for pointing this out.

#14483 report it
rahif at 2013/08/16 03:42am
ajax url

Hi, great extension.

I'd change ajaxUrl to this:

$widget=$this->createWidget('ext.EDataTables.EDataTables', array(
 'id'            => 'products',
 'dataProvider'  => $dataProvider,
 'ajaxUrl'       => $this->createUrl('/products/index'),
 'columns'       => $columns,
));

Now UrlManager create the path acording to yours rules.

Thanks

#13008 report it
le_top at 2013/04/27 02:25pm
Drop in replacement expensive

Hi I agree that this is expensive, which is why I have a MyCGridView wrapper that avoids rendering when not needed (when configured to do so).

The extension should allow both the 'easy' way and the 'optimized way'. The 'easy way' is not that expensive in most cases, and speed of development is preferred. In some cases, optimization is needed. I have such a case and my views/widgets have several checks if rendering of the specific part is needed or not.

Anyway: I know how it is; one makes the extension for his own needs and shares with the community allowing the community to update, while in practice the community still expects the author to update...

#13005 report it
nineinchnick at 2013/04/27 01:56pm
Feedback

Thanks for the feedback. It's always needed. Unfortunately, I don't want to do it the way you describe. EExcelView runs the whole action, then discards its output and generate its own. CGridView, when reloading data through AJAX, renders whole page and then extracts only the table with its contents. It's noted somewhere that this is not a preferred solution but it's there for simplicity. In my projects, rendering whole layout with menus etc. could be quite expensive because of auth checks and such. So there really is a need for a separate action to be called as a data source.

Another thing is performing a database search. There aren't any ready solutions in Yii, you have to create a criteria building mechanism yourself and pass it to dataprovider. I've written my own search() method in ActiveRecord that uses value from sEcho, validates it for every column and then puts it in a criteria object. Its quite complex, including checking auth items for relations etc.

There are lots of things to consider when building an index action and a simple widget doesn't have to cover them all.

Leave a comment

Please to leave your comment.

Create extension