fnRowCallback vs. aoColumns/fnRender

fnRowCallback vs. aoColumns/fnRender

zenbitzzenbitz Posts: 10Questions: 0Answers: 0
edited February 2012 in DataTables 1.8
So I have some JSON tables stored on disk and I am displaying them in datatables. I am inflating some cells based on content (typically creating a link). The first way I did this I used fnRowCallback... and it mostly worked, although turns out I want to use bUseRendered: false... which lead me to doing this in aoColumns instead.

Just got me thinking (not necessarily for this project) - if you are inflating/bloating a cell, do you use fnRowCallback or aoColumns, or "depends".

Replies

  • zenbitzzenbitz Posts: 10Questions: 0Answers: 0
    or aoColumnsDef which I guess is recommended over aoColumsn in docs... but similar question
  • allanallan Posts: 63,692Questions: 1Answers: 10,500 Site admin
    It depends :-)

    There are three ways of manipulating data for display in the table:

    - fnRender .
    - fnRowCallback / fnDrawCallback / fnCreatedCell / fnCreatedRow .
    - mDataProp .

    By far the most flexible is mDataProp as a function (which I plan to write a blog post about soon). fnRowCallback and friends are mainly used to manipulate the DOM (add event listeners, attributes to nodes etc) - you could use them to manipulate the display, but if you want to do that fnRender is probably the way to go ( bUseRendered is an option to extend fnRender's capabilities, but without doubt mDataProp as a function is what I would recommend over bUseRendered now - it does make the code a little bit more complex though, since you need to write a get/set function for the columns which you want to use it on.

    So as I say, it depends a bit on what you want to do.

    > aoColumnsDef / aoColumns

    Again it depends. aoColumnDefs is a lot more flexible since you don't need to specify the exact number of columns, but at times it can be useful to do exactly that, when using aoColumns would make sense.

    There are no hard and fast rules to either answer and the best and optimal method will depend upon the application that is required!

    Allan
  • zenbitzzenbitz Posts: 10Questions: 0Answers: 0
    Thanks. I thought about using mDataProps, but I didn't want to rewrite my JSON spewing backend to give objects instead of array of arrays. Maybe I misread the docs.

    Not getting bUseRendered to work, but probably did something dopey.
  • allanallan Posts: 63,692Questions: 1Answers: 10,500 Site admin
    mDataProp can be used with array integers as well if you want, but bUseRendered should work okay! bUseRendered, when false (it is true by default) will tell DataTables show the rendered string, but use the unrendered data for sorting / filtering.

    Allan
  • zenbitzzenbitz Posts: 10Questions: 0Answers: 0
    no I cannot figure it out:
    [code]
    var dtParams = {"bDeferRender":1,"bJQueryUI":"true","sAjaxSource":"\/tmp\/results\/regulome.762dcca774dad9f036e3c1856bedb47b019b7de2.raw.json","bProcessing":"true","bFilter":0,"aaSorting":[[2,"asc"],[0,"asc"]],"aoColumns":[{"sClass":"aligncenter","sTitle":"Coordinate (0-based)","sWidth":"14em"},{"sClass":"aligncenter","sTitle":"dbSNP ID"},{"sClass":"aligncenter","sTitle":"Regulome DB Score (click to see data)","sWidth":"12em"},{"sClass":"aligncenter","sTitle":"Other Resources","sWidth":"17em"}]};

    // aoColumnDefs is added later
    dtParams['aoColumnDefs'] = [
    { "fnRender": function ( oObj ) {
    if (oObj.aData[2] == 7) {
    return 'No Data';
    } else {
    var snp = oObj.aData[0].split(':');
    return ''+oObj.aData[2]+'';
    }
    },
    "bUseRendered": false,
    "aTargets": [ 2 ]
    },
    { "fnRender": function ( oObj ) {
    var content = [];
    _.each(externalURL, function(url,db) {
    if (db == 'dbSNP' ) {
    var rsid = oObj.aData[1];
    if (rsid.match('^rs') ) content.push(''+db+'');
    } else if (db != 'dbSNP') {
    content.push(''+db+'');
    }
    });
    return content.sort().join(" | ");
    },
    "aTargets": [ 3 ]
    }
    ];
    var table = $('#snp_analysis').dataTable(dtParams);
    [/code]

    The html inflating is working fine, but it's not sorting right at all... I took out the bDeferRender: 1 but that make no difference
  • zenbitzzenbitz Posts: 10Questions: 0Answers: 0
    In case it's not clear... sorting on column 2 does not work, it appears to sort based on HTML content of cell (although that's just a guess).

    "Raw" column to is just from the set of [ 7,6,5,4,3b, 3a, 2c,2b,2a, 1f,1e,1d,1c,1b,1a]
    Sorting works fine in an older version (that did not support huge JSON tables, and the HTML rendering was not done via call back)

    [code]
    $('#snp_analysis').dataTable({"bDeferRender":1,"bJQueryUI":"true","aaData":[["chr11:5246957","rs33914668","2a<\/a>","UCSC<\/a> | ENSEMBL<\/a> | dbSNP<\/a>"],["chr11:5248049","rs35004220","4<\/a>","UCSC<\/a> | ENSEMBL<\/a> | dbSNP<\/a>"],["chr14:100741725","rs78077282","4<\/a>","UCSC<\/a> | ENSEMBL<\/a> | dbSNP<\/a>"],["chrX:53101683","rs7881236","2c<\/a>","UCSC<\/a> | ENSEMBL<\/a> | dbSNP<\/a>"]],"bFilter":0,"aaSorting":[[2,"asc"],[0,"asc"]],"aoColumns":[{"sClass":"aligncenter","sTitle":"Coordinate (0-based)","sWidth":"14em"},{"sClass":"aligncenter","sTitle":"dbSNP ID"},{"sClass":"aligncenter","sTitle":"<\/span><\/a>Regulome DB Score","sWidth":"14em"},{"sClass":"aligncenter","sTitle":"Other Resources","sWidth":"18em"}]});
    [/code]
  • zenbitzzenbitz Posts: 10Questions: 0Answers: 0
    dataTables version 1.8.2
  • allanallan Posts: 63,692Questions: 1Answers: 10,500 Site admin
    Can you give me a link to the page? Alternatively I am currently working on a remote debugging tool for DataTables which I hope to get operational later today, which should provide me with the information needed to figure this out.

    Allan
  • zenbitzzenbitz Posts: 10Questions: 0Answers: 0
    production version (correct sorting) is http://regulome.stanford.edu
    dev version (incorrect sorting) is http://regulome.stanford.edu:8080 - at least I hope that port is open to the outside world.

    Click on any of the examples (highlighted above the input box). This is actually even the simpler version (the submit file uses sAjaxSource) but has the same sorting error.

    Thanks for taking the time to look at this... at this point I hope it's a DT bug not some dumb hash key typo on my part.
  • allanallan Posts: 63,692Questions: 1Answers: 10,500 Site admin
    Hmmm - for some reason the "sType" of the column in your second example is being set to be "string", rather than "html" as it is on the production page. However, I'm not clear on what would be causing that - I'll investigate further and let you know what I find. Could you keep that test page up? It's really useful!

    Thanks,
    Allan
  • zenbitzzenbitz Posts: 10Questions: 0Answers: 0
    sure, but I was going to hack on it later today. I guess I can clone the repo somewhere else.
    What's really odd is that unless you have it backwards above, I would expect setting it to "string" would WORK, and "html" to not!
  • zenbitzzenbitz Posts: 10Questions: 0Answers: 0
    I don't know if this helps or confirms bug... BUT when I set sType: html it works. BUT if I set both sType: html AND bUseRendered: false it throws an error: Object 4 has no method "replace" ("line" 30) in the minimized script.

    So, I guess you fixed it! Although sType: "html" is more than a little counter intuitive.
  • allanallan Posts: 63,692Questions: 1Answers: 10,500 Site admin
    sType "html" means that HTML has been detected and it will be treated as such (in this case removed before sorting, filtering etc). "string" means that the content of the cell, regardless of what it is, will be treated as a string - so if it is HTML then all of it will be used to perform the actions, including the <> brackets etc.

    > BUT if I set both sType: html AND bUseRendered: false it throws an error: Object 4 has no method "replace" ("line" 30) in the minimized script.

    Sounds like it will be trying to work on something that is a number or a primitive that is not a string. If you force the sType like this, then pass in non-string data, then this is expected (since indeed, replace is not a method of a string :-) ).

    Allan
  • allanallan Posts: 63,692Questions: 1Answers: 10,500 Site admin
    edited February 2012
    I think I might have a bit of a handle on what is going on now - in your development version you have an fnRender function assigned to column index 2 by aoColumnDefs:

    [code]
    { "fnRender": function ( oObj ) {
    if (oObj.aData[2] == 7) {
    return 'No Data';
    } else {
    var snp = oObj.aData[0].split(':');
    return ''+oObj.aData[2]+'';
    }
    },
    "bUseRendered": false,
    "aTargets": [ 2 ]
    }
    [/code]

    That does not appear to be present in the production version, and this is what is causing the type to be detected as "string". Because you have "bUseRendered": false, it is using the raw data for the type detection - which is 5, 4, "2a" etc, thus finding it as a string, rather than type html.

    At this point a bug in DataTables 1.9.0 comes into play... When sorting non-string data on a string basis, DataTables 1.9.0 will automatically replace the data with an empty string, resulting in unexpected ordering. The fix is for the sorting to check for a 'toString' method for the data, and if present us that - that means that numeric data will be converted property to a string and then used as such.

    I've just committed the fix for this issue and it is available in the 1.9.1.dev nightly ( http://datatables.net/download ). I've also added unit tests to make sure it doesn't happen again :-).

    Thanks for flagging this up!!

    Regards,
    Allan
  • zenbitzzenbitz Posts: 10Questions: 0Answers: 0
    Thanks for helping with it. Seems like should replace the raw ints with strings in that field (they are dumped from perl, so I probably wasn't careful about setting type...) Also, when I return a string that looks like html i,e '' does that get recognized as HTML or should I use some DOM manipulation instead?
  • allanallan Posts: 63,692Questions: 1Answers: 10,500 Site admin
    > Seems like should replace the raw ints with strings in that field

    Sounds be okay now. I think DataTables should be flexible enough to cope with this!

    > when I return a string that looks like html i,e '' does that get recognized as HTML or should I use some DOM manipulation instead?

    If you use bUseRendered:false then the type detection will be based on the original data. If you use bUseRendered:true (or remove it, since true is the default) then the type detection will be based on what is returned.

    Allan
This discussion has been closed.