createdRow in conjunction with dynamic column visibility

createdRow in conjunction with dynamic column visibility

normadizenormadize Posts: 31Questions: 6Answers: 1

Hi,

I implemented a dynamic column visibility to hide/show columns. I also have a handler for the createdRow event which changes a particular column content, let's say I'm making a button out of the text from column 5 and replace the text with it.

Currently in createdRow I check this.api().columns(5).visible() and if true then I proceed to do $('td:eq(5)',row).html('<button>'+data[5]+'</button>') cell content, and if false then I return because otherwise I'd overwrite the current 5th <td> which is not the intended one. But then when I unhide column 5, it comes up as text since I did not run the previous code.

I'd like to be able to run the code and cache the html of the cell in column 5 so that when it's unhidden, it comes up with the intended <button>. What's the best way to do that?

Cheers

Answers

  • headshot9xheadshot9x Posts: 59Questions: 16Answers: 1
  • normadizenormadize Posts: 31Questions: 6Answers: 1
    edited April 2015

    Hi, thanks for replying. I posted a more thorough explanation here: http://stackoverflow.com/questions/29617599/datatables-createdrow-in-conjunction-with-dynamic-column-hide-unhide

    Note that I know I can use the render: function (...) {} option for the column, but I do not want to use that because it affects the raw data of the table and affects filtering and searching - I want the raw data to remain unaffected, which is why I was using the createdRow or rawCallback callbacks.

    The solution I have in mind now is to leave it be and do it on the init and column-visibility events, first checking if the column is visible, then modifying all <td> content.

    I dislike that solution though because I'm sure I should be able to cache the HTML content and allow DataTables to show/hide it without having to re-generate it on every column-visibility events, since it doesn't change ... although I could put a data-done="1" flag on each <td> and skip the cell in the event handlers if .data('done') is true.

    Any suggestions for a faster solution would be very welcome. My table will have many hundreds of rows.

  • allanallan Posts: 61,687Questions: 1Answers: 10,100 Site admin

    The way to handle this is to use the cells().nodes() method. That way you can get the elements for all of the rows, regardless of column visibility and update them as required.

    For example:

    var elements = this.api().cells( row ).nodes();
    
    $( elements[5] ).html( '<button>'+data[5]+'</button>' );
    

    Allan

  • normadizenormadize Posts: 31Questions: 6Answers: 1
    edited April 2015

    Thanks, Allan. I take it that goes in rowCallback or createdRow, correct? My table will be quite big (hundreds of rows, 10+ columns).

    Is there a more efficient way? Could one use column(5).nodes() instead? Would that be faster than parsing each full row like in your example?

    My table receives new data dynamically (I'm doing rows.add(data) then .draw()) ... I take it that createdRow and rowCallback are then called only for the newly created rows, correct?

  • normadizenormadize Posts: 31Questions: 6Answers: 1
    edited April 2015

    Actually that doesn't work, I think I may have been unclear. Assume that the column in question is hidden (visible:false) by default. That means that .cells(row).nodes() will not contain the cells that I'm interested in.

    I want to change the html of a cell regardless of whether the column is visible or not. Do I need to use the column-visibility and/or draw events?

    The data is available somewhere, because I passed to the constructor ... isn't there a way to alter the html of a hidden column without using the column-visibility or draw events?

  • normadizenormadize Posts: 31Questions: 6Answers: 1
    edited April 2015

    I found a solution. Calling .column(5).nodes() returns the actual nodes of the intended column even if it's hidden by default, so I can do .column(5).nodes().each(function (cell,i) {...}).

    However, I don't have direct access to the row data for the corresponding cell so I'm doing some gymnastics to get the data at that row, which seem suboptimal:

    DT.column(5, {order: 'original'}).nodes().each(function (cell,i) {
        $(cell).html('<button>' + DT.data()[i][5] + '</button>'
    })
    

    I'm forcing original order, then DT.data()[i][5] is the data from row i and column 5. It works, but any suggestions to improve it are welcome!

  • allanallan Posts: 61,687Questions: 1Answers: 10,100 Site admin

    This is a fairly redundant example in that it doesn't do any good, other than to show how what you are looking for might be achieved: http://live.datatables.net/rupipexu/1/edit .

    I've used columns.createdCell, but you could also use createdRow - they will be equally as efficient.

    Using rowCallback is probably the least efficient, since it will be called every time the row is displayed, even if it has been displayed before.

    Another option, if you are just using static HTML is yo use the columns.render option: http://live.datatables.net/rupipexu/2/edit . This is more efficient, but it doesn't give access to the nodes, which may or may not be important for you.

    Allan

  • normadizenormadize Posts: 31Questions: 6Answers: 1

    Hi Allan, thanks for the replies, I'll look into the alternative you suggested. Note that the column is hidden by default.

    I am using render for other columns, but it changes the data that I can get when creating <select> filters in the footer where I want to sort+unique the actual raw data, not the rendered one ... is there a way to do that on the raw data provided render has changed it?

  • allanallan Posts: 61,687Questions: 1Answers: 10,100 Site admin

    Note that the column is hidden by default.

    As it is in my demos. I've made it visible using the API after the initialisation.

    am using render for other columns, but it changes the data that I can get when creating <select> filters in the footer where I want to sort+unique the actual raw data

    Can you give me a link to an example showing that issue please?

    Allan

  • normadizenormadize Posts: 31Questions: 6Answers: 1
    edited April 2015

    Yes, I'm adding a <select> filter for each column like this:

    column.cache('search').sort().unique().each(function (d, j)
    {
        $('<option>').text(d).val(d).appendTo(select);
    });
    

    The reason for using column.cache('search') and not column.data().flatten() is that I want the user to see the render-ed values int he select dropdown, since I have many columns for which the raw data is not human readable (e.g. identifiers, country codes, etc), which I parse into human readable in the render callback.

    I haven't looked closely into using orthogonal data but another possibility is to use render with a function, i.e. render: function (data, type), and checking type in order to return different things for sort, display and filter.

  • normadizenormadize Posts: 31Questions: 6Answers: 1

    Ah, I remember why I really wanted to avoid the render callback: I'm also using TableTools which exports the 'display' value instead of the raw data, which sometimes has the same value for all rows (because it's a button saying "Edit" with a value=<id>). So I'd have to find a way to make TableTools export the 'sort' or 'filter' data ... and I've already spend a lot of time on this issue :)

  • allanallan Posts: 61,687Questions: 1Answers: 10,100 Site admin

    So I'd have to find a way to make TableTools export the 'sort' or 'filter' data

    Here - change it to filter.

    As you can see that isn't externally configurable at the moment unfortunately. Should be easier in TableTools' replacement.

    Allan

  • normadizenormadize Posts: 31Questions: 6Answers: 1

    Thanks. What is TableTools' replacement? Something you guys are cooking up at the moment?

  • allanallan Posts: 61,687Questions: 1Answers: 10,100 Site admin

    I'm splitting TableTools into two new extensions "Buttons" and "Select" (I lack imagination when it comes to names...). Both will be focusing on using and extending the DataTables 1.10 API and ditching a lot of the legacy stuff :-).

    Both are coming on fairly nicely and I hope to be able to release them next month.

    Allan

  • normadizenormadize Posts: 31Questions: 6Answers: 1

    That sounds great! You wrote some great code until now so I'm sure they'll be awesome.

    Regarding names, it's best to use names for which search engines quickly bring up relevant results when people search for help ... maybe "DTButtons" and "DTSelect" are a better choice?

  • allanallan Posts: 61,687Questions: 1Answers: 10,100 Site admin

    Good point. I would imagine most searches will be qualified with the word "datatables" so it might not be too much of an issue, and I wanted the names to be short and simple, but it is something I will think about properly before deploying!

    Allan

This discussion has been closed.