A 3 dimensional table :)
A 3 dimensional table :)
VladBronxi
Posts: 3Questions: 0Answers: 0
Hi,
First, DataTables is really a great piece of work. Thanks a lot!
What I try to achieve is not just have text in TD cells, but more information that will be used e.g. for click functions.
A cell should contain for example an image, and when this image is clicked other parameters (like language or an ID from the MySQL in the backend) which should already be associated with the image ("object") should be ready for click functions.
The "dirty" (but working) way is just to include the appropriate HTML in the JSON, so the Server returns:
{"aaData":[
[
"Row A text",
"[9]",
"10:15 ",
]
,[
"Row B text ",
"[10]",
"06:30 ",
]
so the third column should only display the time (not date), but the click function needs the whole date and the internal ID. I hijackecd the id and alt attributes. - not pretty.
I'd like to have a "cleaner" solution (no HTML on the serverside - not using the ALT tag for my purpuses) is to return a JSON object like:
{"aaData":[
[
"Row A text",
"",
"[9]",
{
"Object" : {
"TypeOfEdit" : "changelanguage",
"Display" : "10:15",
"Data" : "2010-08-27 10:15",
"MySQLID" : "7"
}
},
]
,[
"Row B text ",
"",
"[10]",
{
"Object" : {
"TypeOfEdit" : "changelanguage",
"Display" : "10:15",
"Data" : "2010-08-26 10:15",
"MySQLID" : "9"
}
]
My current approach is to change the received JSON before sending it to datatables, storing the original one and using the drawback function to add the data (as jQuery.data() - haven't figured that out yet).
However, isn't there a better way to achieve something like this - maybe I need to write a plugin? (don't really know where to start - hook that into).
Hope all of this makes some sense :)
Thanks
Martin
current Code:
[code]
function loadtable (cfg,finish) {
var filter = {};
var oTable;
var origtablejson;
if("filter" in cfg) {
$.extend(filter,cfg["filter"]);
}
$.getJSON( cfg["ajax_load"], filter, function (tablejson){
origtablejson = $.extend({},tablejson);
for (var i = 0; i < tablejson.aaData.length; i++) {
for (var j=0; j< tablejson.aaData[i].length;j++){
if (typeof tablejson.aaData[i][j] == "object"){
tablejson.aaData[i][j] = tablejson.aaData[i][j].editable.Display;
}
}
}
initotable(tablejson);
});
function initotable (json) {
oTable=$(cfg["table"]).dataTable( {
"fnDrawCallback": function(oSettings) {
// for marking row
$(cfg["table"] + " tbody").click(function(event) {
$(oTable.fnSettings().aoData).each(function (){
$(this.nTr).removeClass('row_selected');
});
$(event.target.parentNode).addClass('row_selected');
});
/* Developed by VLAD! remove header */
if (cfg['hideheads'] == "true"){
$('thead tr').hide();
};
/* by Vlad: when class=editable search for object data */
$(".editable").addClass("test"); // WORK IN PROGRESS
if ("drawCallback" in cfg && typeof(cfg["drawCallback"]) == "function") {
cfg["drawCallback"](oSettings);
}
}, // end drawback function
"bProcessing": false,
"bPaginate": cfg["bPaginate"],
"sDom": cfg["sDom"],
"bSortClasses": false,
"bAutoWidth": false,
"sPaginationType": "full_numbers",
"bJQueryUI": true,
"oLanguage": {"sUrl": cfg["ajax_load_DTlang"]},
"aaData": json.aaData,
"aoColumns": json.aoColumns
} ); // end oTable
... some handlers and functins omitted
[/code]
First, DataTables is really a great piece of work. Thanks a lot!
What I try to achieve is not just have text in TD cells, but more information that will be used e.g. for click functions.
A cell should contain for example an image, and when this image is clicked other parameters (like language or an ID from the MySQL in the backend) which should already be associated with the image ("object") should be ready for click functions.
The "dirty" (but working) way is just to include the appropriate HTML in the JSON, so the Server returns:
{"aaData":[
[
"Row A text",
"[9]",
"10:15 ",
]
,[
"Row B text ",
"[10]",
"06:30 ",
]
so the third column should only display the time (not date), but the click function needs the whole date and the internal ID. I hijackecd the id and alt attributes. - not pretty.
I'd like to have a "cleaner" solution (no HTML on the serverside - not using the ALT tag for my purpuses) is to return a JSON object like:
{"aaData":[
[
"Row A text",
"",
"[9]",
{
"Object" : {
"TypeOfEdit" : "changelanguage",
"Display" : "10:15",
"Data" : "2010-08-27 10:15",
"MySQLID" : "7"
}
},
]
,[
"Row B text ",
"",
"[10]",
{
"Object" : {
"TypeOfEdit" : "changelanguage",
"Display" : "10:15",
"Data" : "2010-08-26 10:15",
"MySQLID" : "9"
}
]
My current approach is to change the received JSON before sending it to datatables, storing the original one and using the drawback function to add the data (as jQuery.data() - haven't figured that out yet).
However, isn't there a better way to achieve something like this - maybe I need to write a plugin? (don't really know where to start - hook that into).
Hope all of this makes some sense :)
Thanks
Martin
current Code:
[code]
function loadtable (cfg,finish) {
var filter = {};
var oTable;
var origtablejson;
if("filter" in cfg) {
$.extend(filter,cfg["filter"]);
}
$.getJSON( cfg["ajax_load"], filter, function (tablejson){
origtablejson = $.extend({},tablejson);
for (var i = 0; i < tablejson.aaData.length; i++) {
for (var j=0; j< tablejson.aaData[i].length;j++){
if (typeof tablejson.aaData[i][j] == "object"){
tablejson.aaData[i][j] = tablejson.aaData[i][j].editable.Display;
}
}
}
initotable(tablejson);
});
function initotable (json) {
oTable=$(cfg["table"]).dataTable( {
"fnDrawCallback": function(oSettings) {
// for marking row
$(cfg["table"] + " tbody").click(function(event) {
$(oTable.fnSettings().aoData).each(function (){
$(this.nTr).removeClass('row_selected');
});
$(event.target.parentNode).addClass('row_selected');
});
/* Developed by VLAD! remove header */
if (cfg['hideheads'] == "true"){
$('thead tr').hide();
};
/* by Vlad: when class=editable search for object data */
$(".editable").addClass("test"); // WORK IN PROGRESS
if ("drawCallback" in cfg && typeof(cfg["drawCallback"]) == "function") {
cfg["drawCallback"](oSettings);
}
}, // end drawback function
"bProcessing": false,
"bPaginate": cfg["bPaginate"],
"sDom": cfg["sDom"],
"bSortClasses": false,
"bAutoWidth": false,
"sPaginationType": "full_numbers",
"bJQueryUI": true,
"oLanguage": {"sUrl": cfg["ajax_load_DTlang"]},
"aaData": json.aaData,
"aoColumns": json.aoColumns
} ); // end oTable
... some handlers and functins omitted
[/code]
This discussion has been closed.
Replies
it seems to be working with fnRender.
A few points I noticed:
fnRender works on the data BEFORE the function is called (resets any objects/arrays to strings)
fnRender expects a string back - would be great to have the option to return a DOM object.
but again I am really impressed by datatables. there is just nothing you can't do :)
The only thing at the moment is that fnReloadAjax doesn't seem to work anymore - but that needs to wait for tomorrow...
Any suggestions are more than welcome :)
current code:
[code]
function loadtable (cfg,finish) {
var filter = {};
var oTable;
var origtablejson;
var render={};
if("filter" in cfg) {
$.extend(filter,cfg["filter"]);
}
$.getJSON( cfg["ajax_load"], filter, function (tablejson){
render["fnRender"]=WTrender;
// if sclass is defined and "editable" add render function to json
for (var i = 0; i < tablejson.aoColumns.length; i++) {
if (tablejson.aoColumns[i].sClass && tablejson.aoColumns[i].sClass == "editable"){
$.extend(tablejson.aoColumns[i],render);
}
}
// still need to save the original json, as datatables resets the
// objects to string BEFORE calling fnRender
origtablejson = $.extend(true,{},tablejson);
initotable(tablejson);
});
function initotable (json) {
oTable=$(cfg["table"]).dataTable( {
"fnDrawCallback": function(oSettings) {
... few options skipped...
// set data for edit objects
for (var i = 0; i < $(cfg["table"] + " .call_WT_edit").length; i++) {
var cellid = $(cfg["table"] + " .call_WT_edit")[i].id;
var datatoadd = origtablejson.aaData[cellid.split(/_/)[2]][cellid.split(/_/)[4]].editable;
$(cfg["table"] + " #" + cellid).data(datatoadd)
}
// add clickhandler for edit objects
$(cfg["table"] + " .call_WT_edit").click(function(event) {
WT_edit("Lang",$(this).data().Data, $(this).data().WTID,
$(this).data().TypeOfEdit,"false",cfg,function (){
oTable.fnReloadAjax(cfg["ajax_load"]);
})
return false;
});
}, // end drawback function
"bProcessing": false,
"bPaginate": cfg["bPaginate"],
"sDom": cfg["sDom"],
"bSortClasses": false,
"bAutoWidth": false,
"sPaginationType": "full_numbers",
"bJQueryUI": true,
"oLanguage": {"sUrl": cfg["ajax_load_DTlang"]},
"aaData": json.aaData,
"aoColumns": json.aoColumns
} ); // end oTable
// rendering function
function WTrender (oSettings){
var orig=origtablejson.aaData[oSettings.iDataRow][oSettings.iDataColumn];
if (typeof orig == "string"){
return oSettings.aData[oSettings.iDataColumn]
}else{
var content=orig.editable.Data;
/*
* it would be great to attach the data to the image here
* however, the calling function expects a string and the object is
* not in the DOM yet. so we need to attach the data later
* to make things easier we identifiy this image with (from instance)
* plus row plus column ID - to make sure we get the right data from origtablejson
*/
content += " ";
return content;
}
}
[/code]
I changed (approx. line 2457 of datatables):
[code]
/* Cast everything as a string - this allows us to treat everything accurately in the
* sorting functions
*/
if ( typeof aData[i] != 'string' )
{
aData[i] += "";
}
aData[i] = $.trim(aData[i]);
if ( typeof oSettings.aoColumns[i].fnRender == 'function' )
{
var sRendered = oSettings.aoColumns[i].fnRender( {
"iDataRow": iThisIndex,
"iDataColumn": i,
"aData": aData,
"oSettings": oSettings
} );
nTd.innerHTML = sRendered;
if ( oSettings.aoColumns[i].bUseRendered )
{
/* Use the rendered data for filtering/sorting */
oSettings.aoData[iThisIndex]._aData[i] = sRendered;
}
}
else
{
nTd.innerHTML = aData[i];
}
[/code]
to this code
[code]
if ( typeof oSettings.aoColumns[i].fnRender == 'function' )
{
/*
* in regards to "cast everything as string" - in this case
* the fnRender function is responsible
*/
var sRendered = oSettings.aoColumns[i].fnRender( {
"iDataRow": iThisIndex,
"iDataColumn": i,
"aData": aData,
"oSettings": oSettings
} );
nTd.innerHTML = sRendered;
if ( oSettings.aoColumns[i].bUseRendered || typeof aData[i] != 'string' )
{
/* Use the rendered data for filtering/sorting */
oSettings.aoData[iThisIndex]._aData[i] = sRendered;
}
}
else
{
/* Cast everything as a string - this allows us to treat everything accurately in the
* sorting functions
*
* changed bay VLAD: this was originally BEFORE fnRender function check
*/
if (typeof aData[i] != 'string') {
aData[i] += "";
}
aData[i] = $.trim(aData[i]);
nTd.innerHTML = aData[i];
[/code]
I know I shouldn't make any changes to the main script - but if someone uses a custom fnRender function he might also have custom data (not strings). This is much more convenient now as I don't need to store the original JSON data separately.
However, once the table is drawn, the "pure original" JSON isn't available either (or I couldn't find it in oSettings?). So I had to add this oSetting manually:
[code]
function WTrender (oSettings){
//var orig=origtablejson.aaData[oSettings.iDataRow][oSettings.iDataColumn];
if (typeof oSettings.aData[oSettings.iDataColumn] == "string"){
return oSettings.aData[oSettings.iDataColumn]
}else{
var content=oSettings.aData[oSettings.iDataColumn].editable.Data;
// store data in aoData - only if not done so already
if (! oSettings.oSettings.aoData[oSettings.iDataRow].original) {
var origdata;
origdata = $.extend(true, {}, oSettings.aData);
oSettings.oSettings.aoData[oSettings.iDataRow]["original"] = origdata;
}
/*
* it would be great to attach the data to the image here
* however, the calling function expects a string and the object is
* not in the DOM yet. so we need to attach the data later
* to make things easier we identifiy this image with (from instance)
* plus row plus column ID - to make sure we get the right data from origtablejson
*/
content += " ";
return content;
}
}
[/code]
Everything works really great! (always open for suggestions - e.g. if the original JSON is "somewhere") and thanks a lot to Allan!
I hope there is at least ONE person who can benefit from my monologue here :)
Thanks
Martin
To turn this into a dialogue (... :-) ), thanks for your posts - very interesting indeed. I'm not 100% happy with the fnRender API (barely 10% happy with it to be honest), it was a poor decision way back in the 1.0 days. It's a nice little change you've got in there, and I'll certainly consider it for future enhancements. It took me a lot of thinking to convinced myself about the 'casting' of strings there for 1.7, and I like this approach. Marked on the to-do list...
Regards,
Allan