formatting AFTER datatables is totally finished drawing

formatting AFTER datatables is totally finished drawing

rcwalshrcwalsh Posts: 12Questions: 0Answers: 0
edited September 2010 in General
Hi Allan,

Thanks again for your response to my other post a while back. I'm very impressed by your tool and site and was also impressed that you were able to help me so quickly!

I'm again stuck with something even though I've searched the forums for hours. But my problem is probably something you know how to do off the top of your head.

I'm trying to manipulate my table AFTER DataTables is 100% finished drawing it, and I can't figure out a trigger for that. fnDrawCallback doesn't seem to give me what I need. I put some functions into that, and they ended up getting undone by some other process in DataTables that must happen after that trigger point.

Two examples of things I'm trying to do:

[code]
/*I have moved the pagination buttons to different spots on the screen and want to be able to control the CSS class of those buttons and thought I could use jquery to first check the enabled/disabled state of the buttons, but apparently fnDrawCallback gets called too early (ie. before the enabled/disabled state is written into the items' classes).*/
var backEnabled= $("#listings_previous").hasClass('paginate_enabled_previous');
var fwdEnabled= $("#listings_next").hasClass('paginate_enabled_next');
if(backEnabled) $("#listings_previous").addClass('paginate_enabled_previous');
if(fwdEnabled) $("#listings_next").addClass('paginate_enabled_next');

/*I have a dropdown box inside a column header that allows the user to filter results based on their timePosted value. This feature works except that when the table is done drawing, it reverts the dropdown's shown value to its default rather than leaving it as what the user chose. I even tried adding lines of code inside this "change" function to save the chosen value to a cookie and then after the draw use jquery to read from the cookie and re-choose that value in the dropdown. This works but then immediately gets cleared by DataTables somehow.*/
$('#timePosted').change( function()
{
oTable.fnDraw();
} );
[/code]

And if it matters, I'm using server-side processing.

Does DataTables have a callback/trigger signifying that it is TOTALLY finished (so that I can then use jquery to do what I want)?

Thanks so much for your help!
Ryan

Replies

  • allanallan Posts: 63,205Questions: 1Answers: 10,415 Site admin
    Internally how it works with DataTables is that the array 'aoDrawCallback' stores all the functions that the must be called at the end of a draw. This includes the dev defined fnDrawCallback - which is stored at the start of the array, so it is called first. One of the other functions which is called by this array is the pagination update function - hence why your classes are being over written.

    Possibly the easiest thing to do is to simply reverse the direction of the array that is being looped over ( for ( i=0, iLen=oSettings.aoDrawCallback.length ; i
  • rcwalshrcwalsh Posts: 12Questions: 0Answers: 0
    Hi Allan, thanks for your help so far. I still must be missing something because reversing the order of the callbacks still didn't work.

    I then tried just "pushing" onto the callback array a call to my function right before that loop through the callback functions. That didn't work.

    And I also just tried a couple other things.

    This was the method I most expected to work: I tried adding a line at the end of the code of _fnDraw:

    [code]
    function _fnDraw( oSettings )
    {
    //Here is where all your original code is, and I left all of it intact and then just added a line at the bottom.
    //...
    //...
    /* Draw is complete, sorting and filtering must be as well */
    oSettings.bSorted = false;
    oSettings.bFiltered = false;
    postDraw();//Here is where I call my custom function at the very end of the draw. It works, but then something AFTER this (where?) overwrites it.
    }
    [/code]

    And although I didn't expect this to work, I also tried instead adding that one line to the bottom of _fnAjaxUpdateDraw, but that didn't work either.

    What do you think could be happening?

    And thanks for the info on styling, but I think it will be more useful to me to figure out some true "datatables has totally finished its work" callback/trigger point, esp since I'm having trouble not just with the pagination arrows but also with DataTables overwriting my dropdown in the header.

    Thanks for your time!
    Ryan
  • allanallan Posts: 63,205Questions: 1Answers: 10,415 Site admin
    Hi Ryan,

    There shouldn't be anything which is running after the _fnDraw function. There might be another function ending - but they won't be doing anything to the DOM. At least it really shouldn't be - and I can't think of anything that would be (but I could be wrong!).

    I'm very surprised that the postDraw() function didn't work. Is it just server-side processing you are using, or is there anything else fancy going on. I'm struggling to think of what might be happening...

    Also DataTables shouldn't be overwriting any DOM element. Perhaps you could describe what is happening to your header dropdown?

    Allan
  • rcwalshrcwalsh Posts: 12Questions: 0Answers: 0
    Hmm I think I just got a clue. To test whether the draw had anything to do with the problem, I added a different dropdown box to a different column header and then created a link elsewhere on my page with a click event to change the value of that new dropdown (and this click event is in no way connected to a redrawing of the table). On the click, this new dropdown's value didn't change either! So this particular part of my problem doesn't seem related to the draw event.

    The only "fancy" thing that I can think of (and that this new testing made me think of) is that I'm using http://datatables.net/release-datatables/extras/FixedHeader/index.html. So maybe a process within that is caching whatever the header looked like at one point in time and then isn't getting updated when the dropdown changes?

    As for the pagination arrows not working, I think that's unrelated.

    In my postDraw function, I have a line:
    [code]var backEnabled= $("#listings_previous").hasClass('paginate_enabled_previous');[/code]
    And it still doesn't seem to be figuring out at the end of the draw whether that class is there. It's inconsistent.

    Thanks!
    Ryan
  • allanallan Posts: 63,205Questions: 1Answers: 10,415 Site admin
    With FixedHeader, events in the header can be a little tricky - but do-able. The easiest way is to make sure that you use jQuery (not DOM0 - i.e. onClick etc) to bind the events, before you initialise FixedHeader.

    When you say backEnabled is inconsistent, what you you mean? Is it true, when you would expect false and vice versa?

    Allan
  • rcwalshrcwalsh Posts: 12Questions: 0Answers: 0
    To ensure that FixedHeader was related to the problem, I tried temporarily removing it, and indeed the header dropdowns worked fine. So it's correct that FixedHeader was causing the trouble. So now I've re-enabled FixedHeader and am trying to figure out what is wrong.

    I assume since you said that I needed to use jQuery to bind the header dropdown change event before initializing FixedHeader that you mean I should do this:
    [code]
    $('#timePosted').change( function()
    {
    timePosted=$(this).val();
    $.cookie("timePosted", timePosted);
    oTable.fnDraw();
    } );
    new FixedHeader( oTable );//calling this AFTER binding the "change" event.
    [/code]
    But that's what I have, and it's still not working.

    For the backEnabled:

    Suppose you have a table of 100 rows showing 10 per page. On the first page, the "back" arrow is disabled, and the fwd arrow is enabled, and my postDraw function gets it right. But when you click to the next page, my postDraw function still thinks the arrows are the same (ie. that back is disabled and fwd is enabled). Then if you're on page 2 or 3 or somewhere in the middle there and do a hard refresh (CTRL-F5), my postDraw will think that both arrows are enabled (which is true), but then as you page back to the first page, where you'd hope that postDraw would then know that the back arrow should be disabled, it still thinks it's enabled. So basically, postDraw is only checking the status of an arrow one time (whenever the js was downloaded first), and then no matter where you flip the page, it will still think the arrows should be the same. If I haven't explained this well, please let me know.

    Thanks!
    Ryan
  • allanallan Posts: 63,205Questions: 1Answers: 10,415 Site admin
    FixedHeader - that looks right. I would have expected that to work. Can you link us to an example which is showing this problem please?

    backEnabled: I think I'm getting a little lost here as well :-). Again it rather sounds like it should be working... Again an example would be really helpful if you can put one up.

    Thanks,
    Allan
  • rcwalshrcwalsh Posts: 12Questions: 0Answers: 0
    Hi Allan,

    I'm not able to give a link yet since my site isn't working, though I could send source files to an email address of yours.

    Good news about the pagination buttons: I was able to get them working in my postDraw function by doing some funky jQuery (below).

    The code below clones the DataTables pagination buttons twice (so one set is at the top corners of the table and one set is at the bottom corners of the table) and then hides the original set so that only the 4 buttons at the 4 corners are visible. The clones are "deep" so that the functionality still works. I also then shrunk the ones at the top since I don't need those to be as large.

    [code]
    $("#listings_previous,#listings_next").css("width","45px").css("height","45px");

    $("#paginationCenter").append($("#listings_info"));
    $("#newLenLoc").append($("#listings_length"));
    $("#leftPagination").html('');
    $("#topLeftPagination").html('');
    $("#rightPagination").html('');
    $("#topRightPagination").html('');
    $("#listings_previous").clone(true).appendTo($("#leftPagination"));
    $("#listings_previous").clone(true).appendTo($("#topLeftPagination"));

    $("#listings_next").clone(true).appendTo($("#rightPagination"));
    $("#listings_next").clone(true).appendTo($("#topRightPagination"));

    origImg=$("#topLeftPagination div").css("background-image");
    newImg=origImg.replace(".jpg", "_sm.jpg");
    $("#topLeftPagination div").css("background-image",newImg);

    origImg=$("#topRightPagination div").css("background-image");
    newImg=origImg.replace(".jpg", "_sm.jpg");
    $("#topRightPagination div").css("background-image",newImg);

    $("#topLeftPagination div,#topRightPagination div").css("width","30px").css("height","30px");
    $("#listings_paginate").hide();
    [/code]

    I still haven't figured out why FixedHeader won't let me have a dropdown in the header cell, so I'll keep looking at that.

    Thanks,
    Ryan
  • rcwalshrcwalsh Posts: 12Questions: 0Answers: 0
    Actually, here is an improvement on the above code, since the top arrows in the above code were doing double-page-flips.

    This version removes IDs when cloning and also unbinds.

    [code]
    function postDraw()
    {
    $("#listings_paginate").hide();
    $("#listings_previous,#listings_next").css("width","45px").css("height","45px");

    $("#paginationCenter").append($("#listings_info"));
    $("#newLenLoc").append($("#listings_length"));

    //clear out these corners so that they don't keep getting appended/doubled every redraw
    $("#leftPagination").html('');
    $("#topLeftPagination").html('');
    $("#rightPagination").html('');
    $("#topRightPagination").html('');

    //clone the original pagination buttons but without the IDs
    $("#listings_previous").clone(true).removeAttr("id").appendTo($("#leftPagination"));
    $("#listings_previous").clone(true).removeAttr("id").appendTo($("#topLeftPagination"));
    $("#listings_next").clone(true).removeAttr("id").appendTo($("#rightPagination"));
    $("#listings_next").clone(true).removeAttr("id").appendTo($("#topRightPagination"));

    origImg=$("#topLeftPagination div").css("background-image");
    newImg=origImg.replace(".jpg", "_sm.jpg");
    $("#topLeftPagination div").css("background-image",newImg);//replace background-image with smaller one

    origImg=$("#topRightPagination div").css("background-image");
    newImg=origImg.replace(".jpg", "_sm.jpg");
    $("#topRightPagination div").css("background-image",newImg);//replace background-image with smaller one

    $("#topLeftPagination div,#topRightPagination div").css("width","30px").css("height","30px").unbind();//make div smaller and not double-bound to click-event
    }
    [/code]


    I put a call to postDraw() in the minified dataTables code here:
    [code]
    //...
    a.aoDrawCallback[b].fn.call(a.oInstance,a);a.bSorted=false;a.bFiltered=false}postDraw();/*call postDraw at very end of draw*/}
    [/code]
This discussion has been closed.