Dynamically created header/footer
Dynamically created header/footer
Hi Allan
I am generating aoColumnDefs server-side and then rendering as normal. For some columns I would like a select filter header, for some an input filter header and for some no filter. I have been playing with a function in fnInitComplete, going through all the aoColumnDefs and creating a footer for each but I can't see an easy way to decide what type of filter to apply
I can't see anything obvious in the docs, can I achieve this using aoColumnDefs maybe something like
[code]
'mData': columnName,
'sClass': niceClass,
'footerType': 'select|input|null',
[/code]
I am generating aoColumnDefs server-side and then rendering as normal. For some columns I would like a select filter header, for some an input filter header and for some no filter. I have been playing with a function in fnInitComplete, going through all the aoColumnDefs and creating a footer for each but I can't see an easy way to decide what type of filter to apply
I can't see anything obvious in the docs, can I achieve this using aoColumnDefs maybe something like
[code]
'mData': columnName,
'sClass': niceClass,
'footerType': 'select|input|null',
[/code]
This discussion has been closed.
Replies
In fnInitCallback you get the JSON from the server (second parameter) so you could loop over your column definitions in that function and add the required markup for the filters there, based on your extra parameters in the JSON object (such as footerType).
Allan
I've got this working using the method discussed; I've added a row in the table header containing the filters for each column. However, when I call oTable.fnFilter it also applies the filter to the thead and so the row with my filters disappears! Any thoughts on how to get round this please?
Would you mind sharing more details on how you are generating aoColumnDefs in server-side to create thead dynamically?
[quote]flarpy said: I am generating aoColumnDefs server-side and then rendering as normal. [/quote]
[code]
$('#programtable').find('thead').prepend('');
for (var e in settings.aoColumns) {
if (settings.aoColumns[e].bVisible == false) {
continue;
}
if (settings.aoColumns[e].filter != false) {
var myCells = $('.'+settings.aoColumns[e].mData);
var innerHTML = fnCreateSelect( oTable.fnGetColumnData(settings.aoColumns[e].mData) );
console.log(innerHTML);
var property = settings.aoColumns[e].mData;
$('#programtable').find('thead tr:first').append(''+innerHTML+'');
$('select').change( function () {
oTable.fnFilter( $(this).val(), findColumnNumber(property) );
} );
} else {
$('#programtable').find('thead tr:first').append('test');
}
}
[/code]
Not sure I quite understand I'm afraid. The fnFilter method will apply the filter, but the only place outside the tbody it will effect is the global filtering input, and it will only effect that if you are doing a global filter, rather than a column based filter. fnFilter shouldn't be modifying anything in the thead.
Allan
1. Array of objects that represent columns
2. Encode object array into JSON
3. Method to parse JSON to conform to aoColumnDef format
[code]
public static function columns(array $filter = array())
{
$columns = array(
'userAction' => new programColumn(array(
'name' => 'userAction',
'label' => '',
'format' => 'string',
'bSortable' => false,
'fieldName' => '',
'removable' => false,
'jsRenderFunction' => 'renderAction(data, type, row);',
'headerLabel' => _('Action'),
)),
'name' => new programColumn(array(
'name' => 'name',
'label' => _('Program'),
'format' => 'string',
'sortDir' => 'asc',
'fieldName' => 'name',
'jsRenderFunction' => 'renderNames(data, type, row);',
'removable' => false,
)),
'events' => new programColumn(array(
'name' => 'events',
'label' => _('Commissions'),
'format' => 'events',
'sortDir' => 'asc',
'bSortable' => false,
'sWidth' => '150px',
'jsRenderFunction' => 'renderEvents(data, type, row);',
)),
[/code]
[code]
public function datatablesColumnDefinitions(array $columns, array $columnsSelected)
{
$defs = array();
$colNum = 0;
foreach ($columns as $column) {
$def = array(
'mData' => $column->name,
'sTitle' => $column->label,
'sClass' => $column->name,
'bSortable' => isset($column->bSortable) === true ? $column->bSortable : true,
'sWidth' => isset($column->sWidth) === true ? $column->sWidth : '',
'aTargets' => array($colNum),
'filter' => isset($column->filter) === true ? $column->filter : false,
'bVisible' => in_array($column->name, $columnsSelected) === true ? true: false,
);
if ($column->jsRenderFunction !== null) {
$def['mRender'] = 'function (data, type, row) {return ' . $column->jsRenderFunction . '}';
}
$defs[] = (object) $def;
$colNum++;
}
return self::_columnDefsOutput($defs);
}
[/code]
[code]
protected function _columnDefsOutput($defs)
{
$outputString = "[\n";
$ii = 0;
foreach ($defs as $key => $object) {
(isset($object->mRender) === true) ? $myRender = $object->mRender : $myRender = '';
unset($object->mRender);
$thisDef = json_encode($object);
if ($ii > 0) {
$outputString .= ",\n";
}
if ($myRender !== '') {
// we need to render the function definition unquoted, so splice into in here.
$outputString .= str_replace('}', ',"mRender":' . $myRender . '}', $thisDef);
} else {
$outputString .= $thisDef;
}
$ii++;
}
$outputString .= ']';
return $outputString;
}
[/code]
Hi Allan
I have tested this by adding a row into thead (using td not th as cells but either produces the same behaviour).
I then run oTable.fnFilter( 'Automatic', 5);
It correctly filters content but also removes the row with the filters in.
Here is some code to demonstrate
[code]
test
test
test
AutomaticManual
test
test
test
test
test
test
test
test
test
test
test
test
.....
Run oTable.fnFilter( 'Automatic', 5);
.....
[/code]
Allan
I have tried putting the row back with fnDrawCallback but then the filters only contain the item I have just filtered the table by.
Allan
Thanks very much for the code snippet.
I've setup an environment where you can look at this as I'm stumped:) I'll pm you the login details
You've got scrolling enabled - that will do it... The way that DataTables works with scrolling enabled is that it breaks the table into three sections (or two if no footer) - effectively separating the original HTML `table` element into three (or two) different tables.
Thus a jQuery call such as: $('#example thead') doesn't actually refer to the table's 'visible' header, but rather one inside the visual body of the table which is used to ensure column alignment. DataTables, on each draw, obliterates that inner header, in order to keep visual correctness.
So there are a couple of options for how to address this:
1. Get a reference to the thead before initialising the scrolling DataTable and then use that (DataTables moves the original thead into the new header table). So you could do:
[code]
var thead = $('#example thead');
var table = $('#example').dataTable();
var thead.append( '...' ); // with all the filtering magic of course
[/code]
2. You can use the internal cached parameter DataTables uses for the thead element:
[code]
var thead = table.fnSettings().nTHead;
[/code]
3. Use a selector that reflects the modified DOM structure - such as:
[code]
var thead = $('#example_wrapper div.dataTables_scrollHead thead');
[/code]
Regards,
Allan