3

I currently have a DataTable that uses pipelining and I now need it to also use FixedColumns. I can do it in the browser console okay but getting it to work automatically after loading, I am at a loss.

What I have in fnInitComplete:

var someObj = new FixedColumns(oTable, {
                                    "iLeftColumns": 6,
                                    "iLeftWidth": 600
                                  });

though this seems to reload the table or something because fnDrawCallback and fnRowCallback is called quite a bit after this.

EDIT: This is the closest example I can find, however, it does not use pipelining. http://datatables.net/release-datatables/extras/FixedColumns/server-side-processing.html

Tomas
  • 57,621
  • 49
  • 238
  • 373
Ray
  • 2,713
  • 3
  • 29
  • 61
  • not sure what can be your problem. Let's have a look at a basic working example I constructed for you. – Tomas Jan 16 '14 at 15:55

1 Answers1

0

I've put simple working example together. Placing the FixedColumns initialization code into fnInitComplete was enough to make it work:

var oTable = $('#example').dataTable( {
    // ...
    ,"sScrollX": "100%"
    ,"sScrollXInner": "150%"
    ,"fnInitComplete": function () {
        var someObj = new FixedColumns(oTable, {
                    "iLeftColumns": 1,
                    "iLeftWidth": 50
        });
    }
} );

I have constructed an example using the pipe-lining example from datatables and adding the FixedColumns code. I referenced their server side PHP script, and solved the XSS problem by PHP GET proxy. The full test example code is here (you can paste it to your own file):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <!--<base href="http://datatables.net/examples/server_side/"> -->
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <link rel="shortcut icon" type="image/ico" href="http://www.sprymedia.co.uk/media/images/favicon.ico" />

        <title>DataTables example</title>
        <style type="text/css" title="currentStyle">
            @import "http://datatables.net/release-datatables/media/css/demo_page.css";
            @import "http://datatables.net/release-datatables/media/css/demo_table.css";
        </style>
        <script type="text/javascript" language="javascript" src="http://datatables.net/release-datatables/media/js/jquery.js"></script>
        <script type="text/javascript" language="javascript" src="http://datatables.net/release-datatables/media/js/jquery.dataTables.js"></script>
        <script type="text/javascript" charset="utf-8" src="http://datatables.net/release-datatables/extras/FixedColumns/media/js/FixedColumns.js"></script>
        <script type="text/javascript" charset="utf-8">


var oCache = {
    iCacheLower: -1
};

function fnSetKey( aoData, sKey, mValue )
{
    for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
    {
        if ( aoData[i].name == sKey )
        {
            aoData[i].value = mValue;
        }
    }
}

function fnGetKey( aoData, sKey )
{
    for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
    {
        if ( aoData[i].name == sKey )
        {
            return aoData[i].value;
        }
    }
    return null;
}

var hadSomeData = false;

function fnDataTablesPipeline ( sSource, aoData, fnCallback ) {
    var iPipe = 5; /* Ajust the pipe size */

    var bNeedServer = false;
    var sEcho = fnGetKey(aoData, "sEcho");
    var iRequestStart = fnGetKey(aoData, "iDisplayStart");
    var iRequestLength = fnGetKey(aoData, "iDisplayLength");
    var iRequestEnd = iRequestStart + iRequestLength;
    oCache.iDisplayStart = iRequestStart;

    console.log('pipeline called');
    /* outside pipeline? */
    if ( oCache.iCacheLower < 0 || iRequestStart < oCache.iCacheLower || iRequestEnd > oCache.iCacheUpper )
    {
        bNeedServer = true;
    }

    /* sorting etc changed? */
    if ( oCache.lastRequest && !bNeedServer )
    {
        for( var i=0, iLen=aoData.length ; i<iLen ; i++ )
        {
            if ( aoData[i].name != "iDisplayStart" && aoData[i].name != "iDisplayLength" && aoData[i].name != "sEcho" )
            {
                if ( aoData[i].value != oCache.lastRequest[i].value )
                {
                    bNeedServer = true;
                    break;
                }
            }
        }
    }

    /* Store the request for checking next time around */
    oCache.lastRequest = aoData.slice();

    if ( bNeedServer )
    {
        if ( iRequestStart < oCache.iCacheLower )
        {
            iRequestStart = iRequestStart - (iRequestLength*(iPipe-1));
            if ( iRequestStart < 0 )
            {
                iRequestStart = 0;
            }
        }

        oCache.iCacheLower = iRequestStart;
        oCache.iCacheUpper = iRequestStart + (iRequestLength * iPipe);
        oCache.iDisplayLength = fnGetKey( aoData, "iDisplayLength" );
        fnSetKey( aoData, "iDisplayStart", iRequestStart );
        fnSetKey( aoData, "iDisplayLength", iRequestLength*iPipe );
        console.log('actually asking server!');

        $.getJSON( sSource, aoData, function (json) { 
            /* Callback processing */
            console.log('got back!');
            oCache.lastJson = jQuery.extend(true, {}, json);

            if ( oCache.iCacheLower != oCache.iDisplayStart )
            {
                json.aaData.splice( 0, oCache.iDisplayStart-oCache.iCacheLower );
            }
            json.aaData.splice( oCache.iDisplayLength, json.aaData.length );

            console.log('have data 2! ' + json.aaData.length);
            hadSomeData = true;
            fnCallback(json);
            console.log('after callback');
        } );
    }
    else
    {
        json = jQuery.extend(true, {}, oCache.lastJson);
        json.sEcho = sEcho; /* Update the echo for each response */
        console.log('have data! ' + json.aaData.length);
        json.aaData.splice( 0, iRequestStart-oCache.iCacheLower );
        json.aaData.splice( iRequestLength, json.aaData.length );
        hadSomeData = true;
        fnCallback(json);
        return;
    }

}

$(document).ready(function() {

var fixedColDone = false;

    var oTable = $('#example').dataTable( {
        "bProcessing": true,
        "bServerSide": true,
//      "sAjaxSource": "http://datatables.net/examples/examples_support/server_processing.php",
        "sAjaxSource": "get_proxy.php",
        "fnServerData": fnDataTablesPipeline
        ,"sScrollX": "100%"
        ,"sScrollXInner": "150%"
/*  ,"fnDrawCallback": function () {
        console.log('draw callback');
        if (!fixedColDone && hadSomeData) {
            console.log('actually drawing!');
            var someObj = new FixedColumns(oTable, {
                                    "iLeftColumns": 1,
                                    "iLeftWidth": 50
                                  });       
            fixedColDone = true;
        }
    }*/
    ,"fnInitComplete": function () {
            var someObj = new FixedColumns(oTable, {
                                    "iLeftColumns": 1,
                                    "iLeftWidth": 50
                                  });       
    }
    } );


/*setTimeout(function () {
}, 5000);*/

} );
</script>
    </head>
    <body id="dt_example">
        <div id="container">
            <div class="full_width big">
                <i>DataTables</i> server-side processing with pipelining example
            </div>

            <h1>Preamble</h1>
            <p>When using server-side processing with DataTables, it can be quite intensive on your server having an Ajax call every time the user performs some kind of interaction - you can effectively DDOS your server with your own application!</p>
            <p>This example shows how you might over-come this by modifying the request set to the server to retrieve more information than is actually required for a single page's display. This means that the user can page multiple times (5 times the display size is the default) before a request must be made of the server. Paging is typically the most common interaction performed with a DataTable, so this can be most beneficial to your server's resource usage. Of course the pipeline must be cleared for interactions other than paging (sorting, filtering etc), but that's the trade off that can be made (sending extra information is cheep - while another XHR is expensive).</p>

            <h1>Live example</h1>
            <div id="dynamic">
<table cellpadding="0" cellspacing="0" border="0" class="display" id="example" style="width: 200px;">
    <thead>
        <tr>
            <th width="20%">Rendering engine</th>
            <th width="25%">Browser</th>
            <th width="25%">Platform(s)</th>
            <th width="15%">Engine version</th>
            <th width="15%">CSS grade</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td colspan="5" class="dataTables_empty">Loading data from server</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th>Rendering engine</th>
            <th>Browser</th>
            <th>Platform(s)</th>
            <th>Engine version</th>
            <th>CSS grade</th>
        </tr>
    </tfoot>
</table>
</body>
</html>

And the get_proxy.php (you have to save it into the same directory), derived from https://stackoverflow.com/a/18800645/684229

<?php

$url = 'http://datatables.net/examples/examples_support/server_processing.php'; //Edit your target here

//open connection
$ch = curl_init();

//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url . "?" . $_SERVER['QUERY_STRING']);

//execute post
$result = curl_exec($ch);

//close connection
curl_close($ch);

?>

EDIT: Try to put the initialization like here (remove it from other places):

setTimeout(function () {
    var someObj = new FixedColumns(oTable, {
                "iLeftColumns": 1,
                "iLeftWidth": 50
    });
}, 10000);

and wait 10 seconds. Is it displayed correctly now?

Community
  • 1
  • 1
Tomas
  • 57,621
  • 49
  • 238
  • 373
  • I have the Fixed Columns initialization set in the fnInitComplete however, it seems to be calling fnRowCallback about 50 times after that – Ray Jan 16 '14 at 19:54
  • @Raymond yes, but why should it matter? – Tomas Jan 16 '14 at 20:01
  • i've tried it with a timeout and it works ok, however it will not work as a final solution. (also it cancels out the formatting I do with fnRowCallback; I imagine I can move the formatting to after the fixed columns though) – Ray Jan 17 '14 at 02:39
  • @Raymond OK. But it is very hard to help you if you don't provide the code. I showed an example where it works. You probably do something more which breaks the functionality, but it is hard to tell where if you don't provide more info. Posting whole working example which we can play with would be the best. – Tomas Jan 17 '14 at 10:09
  • I'll see what I can do – Ray Jan 17 '14 at 14:19
  • I've been so busy with other projects. Sorry I haven't been much helpful to you helping me. I will give you bounty and hope that this gets me where I need. If not, I will just comment back. I'm thinking the issue is that my fnRowCallback is getting called too many times. – Ray Jan 23 '14 at 15:09
  • @Raymond thanks. What I would do is a step-by-step simplification of your buggy code down to the example I provided, and see at which step the bug disappears :) This is a very efficient method to find the cause of your problem if you don't have any clues. Thanks to the example I provided you see it's not a problem of the basic library functionality so you can find it by this method in your code. Feel free to come back then. Good luck! – Tomas Jan 24 '14 at 18:33