0
votes

I am writing a code for server side processing for DataTables. I have a UI page where I collect all user input like start / end dates, token ID, batch Id etc. Now I have to pass these values to backend script and run a query and render output to datatables in UI page.

So I have the JS code to take and validate user input but I am not sure how to call / set params for datatables to state server side scripting. Below is my script:

function runreport(datastring)
{
       var oTable = $('#example').dataTable( {
                "bProcessing": true,
                "bServerSide": true,
                "sAjaxSource": "runsearch.py",
                "bDestroy" : true,
                "fnServerData": function ( sSource, aoData, fnCallback ) {
                        $.ajax( {
                                        "dataType": 'json',
                                        "type": "POST",
                                        "url": sSource,
                                        "data": aoData,
                                        "success": function(json) {
                                                $("div#report_result").show();
                                                $('html, body').animate({scrollTop:$(document).height()}, 'slow');
                                                fnCallback(json);
                                        }
                                } );
                 }
        } );
}

I call 'runreport' method when all input params are validated. I construct datastring as like query string : token_id=xxxx&[email protected]&start_date=1212121212&end_date=98989898 but these values are not getting passed? I get the below error:

k is undefined
[Break On This Error]  

...Sorting=="undefined"&&typeof e.saved_aaSorting=="undefined")e.aaSorting[a][1]=k....

jquery....min.js (line 150)

What we should do to have DataTables result generated from a backend script?

I am not getting the result output as desired? Is this the right way to call DataTables functionality for server side processg?

Below is my Python code that dumps static result set:

#!/usr/local/bin/python

import cgi
import MySQLdb
import json

print "Content-Type: application/json"
print

displaylength =5
result = {'iDisplayLength':str(displaylength), 'sPaginationType':'full_numbers', 'bProcessing':1, 'bDestroy': 1, 'bRetrieve':1, 'aaData':[{'First Field':'First Field Value', 'Second Field':'Second Field Value', 'Third Field':'Third Field Value', 'Fourth Field':'Fourth Field Value', 'Fifth Field':'Fifth Field Value', 'Sixth Field':'Sixth Field Value', 'Seventh Field':'Seventh Field Value', 'Eight Field':'Eight Field Value', 'Nineth Field':'Nineth Field Value'}, {'First Field':'First Field Value', 'Second Field':'Second Field Value', 'Third Field':'Third Field Value', 'Fourth Field':'Fourth Field Value', 'Fifth Field':'Fifth Field Value', 'Sixth Field':'Sixth Field Value', 'Seventh Field':'Seventh Field Value', 'Eight Field':'Eight Field Value', 'Nineth Field':'Nineth Field Value'}], 'aoColumns':[{'sTitle':'First Field', 'mDataProp': 'First Field'},{ 'sTitle':'Second Field', 'mDataProp': 'Second Field'}, {'sTitle':'Third Field', 'mDataProp': 'Third Field' }, { 'sTitle':'Fourth Field', 'mDataProp': 'Fourth Field' }, { 'sTitle':'Fifth Field' , 'mDataProp': 'Fifth Field' }, { 'sTitle':'Sixth Field', 'mDataProp': 'Sixth Field' }, { 'sTitle':'Seventh Field', 'mDataProp': 'Seventh Field' }, { 'sTitle':'Eight Field', 'mDataProp': 'Eight Field' }, { 'sTitle':'Nineth Field', 'mDataProp': 'Nineth Field' }]}

json_string = json.dumps(result)
print json_string
3

3 Answers

0
votes

There are multiple ways to do this. DataTables supports AJAX source and therefore you can write a script that will output a json array and pass it to the DataTables plugin.You could also just render the table from PHP.

I would look through some of there examples to see other ways you could pass data to DataTables.

0
votes

aoData.push is what you're looking for. Use this for your fnServerData callback, replacing the name and value in aoData.push for the values you want to pass. Name will be the key and value will be the value, passed as $_REQUEST variables:

"fnServerData": function ( sSource, aoData, fnCallback ) {
        aoData.push({ "name": "var1name", "value": $('#var1').val() },
                    { "var2name": "company_name", "value": $('#var2').val() });

        $.ajax({
            "dataType": 'json',
            "type": "POST",
            "url": sSource,
            "data": aoData,
            "success": fnCallback
         });
}

To test that it's working, make the page that is getting the ajax request simply mail you the $_REQUEST. You should see these variables as part of it.

A common companion to the callback is adding a button to refresh the table. That's simply done by binding the following to a click handler on a refresh button:

oTable.fnDraw(false);

Good luck.

0
votes

Here is some of my C# code of datatables and server-side/client-side

You can use this to translate it to python if you want, I translated this from Alans PHP example

Clientside:

/* Instantiate the Datatables on the ASP.NET GridView */
var dt = $('#gvJobs').dataTable({
    "sDom": 'C<"clear">Rlfrtip', /* ColReOrder, ColVis */
    "bFilter": true, /* Use custom filters, i have to revise this as I am doing the drop down filter manually now */
    "bSort": true,
    "bAutoWidth": false,
    "bProcessing": true, /* Needed, Read Datatables documentation */
    "bServerSide": true, /* Needed, Read Datatables documentation */
    "aaSorting": [[0, "desc"]], /* Initial Default Sorting on the First Column */
    "sPaginationType": "full_numbers",
    "fnServerData": function (sSource, aoData, fnCallback) {
        /* Adding Custom Drop Down Filter property to aoData which will be used server side */
        aoData.push({ name: "ddlStatus", value: $("#ddlStatus option:selected").text() });

        /*  Here I do the PageMethods call (ASP.NETs Ajax Replacement) PageMethods.getData
        "getData" is a Server Side C# Method which looks like this:

        [WebMethod]
        public static string getData(List<oaData> aoData)
        {
        //Method Code
        }

        With page methods you pass in all your parameters matching the server side method,
        And right at the end, add your two callback functions for onsuccess and onerror
        */
        PageMethods.getData(aoData, function (obj) {
            /* On Success, datatables fnCallback with JSON object */
            fnCallback(JSON.parse(obj));
        }, function (XMLHttpRequest, textStatus, errorThrown) {
            /* On Error, show error alert */
            alert(XMLHttpRequest.status + ': ' + XMLHttpRequest.responseText);
        });
    },
    "aoColumns": [
    /*  This (JobNo) my first column which is Custom with 3 Images and a HyperLink to another page,
    The last 5 Columns is hidden from the User because those fields are only used to 
    Render the correct images in this first column, Only used as Eval fields basically

    Note that mDataProp is the GridView column's "DataField" and not the "HeaderText"
    */
        { "mDataProp": "JobNo",
          "fnRender": function (oObj) {
             return "<img src='" + (oObj.aData.HasAttachments ? "css/paperclip-icon.png" : "css/empty-icon.png") + "' height='16px' />"
                    + "<a href='#' onclick=\"gotoJobDetail('" + oObj.aData.JobId + "');\">" + oObj.aData.JobNo + "</a>"
                    + "<img src='" + (oObj.aData.Visited ? "css/yes.png" : "css/no.png") + "' height='16px' />"
                    + "<img src='" + (oObj.aData.Completed ? "css/completed.png" : "css/notcompleted.png") + "' height='16px' />";
            },
            "bUseRendered": true /* This renders the Column in HTML first, else you'd see the actual HTML text in the column */
        },
        {    "mDataProp": "JobStatusName" },
        {    "mDataProp": "StatusDateTime" },
        /* Only used as Eval Field for one of the images in the JobNo Column */
        {    "mDataProp": "HasAttachments",
            "bSearchable": false,
            "bVisible": false
        },
        /* Only used as Eval Field for one of the images in the JobNo Column */
        {"mDataProp": "Visited",
        "bSearchable": false,
        "bVisible": false
        },
        /* Only used as Eval Field for one of the images in the JobNo Column */
        {"mDataProp": "Completed",
        "bSearchable": false,
        "bVisible": false
        },
        /* Just Hidden, not used at the moment neither by the user nor the application */
        {"mDataProp": "JobStatusId",
        "bSearchable": false,
        "bVisible": false
        },
        /* Only used as Eval Field for one of the images in the JobNo Column */
        {"mDataProp": "JobId",
        "bSearchable": false,
        "bVisible": false
        }
    ]
});

Server Side Objects

//INCOMING OBJECT FROM CLIENTSIDE
public class oaData
{
    public string name { get; set; }
    public string value { get; set; }
}

//RETURNING OBJECT TO CLIENTSIDE
public class oaData<T>
{
    public int sEcho { get; set; }
    public int iTotalRecords { get; set; }
    public int iTotalDisplayRecords { get; set; }
    public T aaData { get; set; }
    public string sColumns { get; set; }
}
//THIS IS 'T' IN oaData<T>
public class JobOverviewDynamic
{
    public int JobNo { get; set; }
    public string JobStatusName { get; set; }
    public string StatusDateTime { get; set; }
    public bool HasAttachments { get; set; }
    public bool Visited { get; set; }
    public bool Completed { get; set; }
    public int JobStatusId { get; set; }
    public int JobId { get; set; }
}

Populate the object, then JSON stringify it with Newtonsoft library and return HERE is my Serverside method

[WebMethod]
public static string getData(List<oaData> aoData)
{
    /* The Columns array
     * If the array from Parameters is not empty, then use that
     */
    string[] aColumns = { "JobNo", "JobStatusName", "StatusDateTime", "HasAttachments", "Visited", "Completed", "JobStatusId", "JobId" };
    var newCols = aoData.Where(n => n.name == "sColumns").Select(n => n.value).FirstOrDefault().Split(',');
    aColumns = (newCols.Length == 1 && newCols[0] == "") ? aColumns : newCols;

    /* Paging */
    var iDisplayStart = aoData.Where(n => n.name == "iDisplayStart").Select(n => n.value).FirstOrDefault();
    var iDisplayLength = aoData.Where(n => n.name == "iDisplayLength").Select(n => n.value).FirstOrDefault();

    /* Ordering */
    var sOrder = "";
    var iSortCol_0 = aoData.Where(n => n.name == "iSortCol_0").Select(n => n.value).FirstOrDefault();
    if (iSortCol_0 != null && aColumns.Length > 0)
    {
        sOrder = "ORDER BY  ";
        var iSortingCols = aoData.Where(n => n.name == "iSortingCols").Select(n => int.Parse(n.value)).FirstOrDefault();
        for (int i = 0; i < iSortingCols; i++)
        {
            var iSortCol = aoData.Where(n => n.name == "iSortCol_" + i).Select(n => int.Parse(n.value)).FirstOrDefault();
            var bSortable = aoData.Where(n => n.name == "bSortable_" + iSortCol).Select(n => bool.Parse(n.value)).FirstOrDefault();

            if (bSortable)
            {
                var sSortDir = aoData.Where(n => n.name == "sSortDir_" + i).Select(n => n.value).FirstOrDefault();
                sOrder += aColumns[iSortCol] + " " + sSortDir + ", ";
            }
        }
        sOrder = sOrder.Trim();
        sOrder = sOrder.Substring(sOrder.Length - 1) == "," ? sOrder.Substring(0, sOrder.Length - 1) : sOrder;
        sOrder = (sOrder == "ORDER BY") ? "" : sOrder;
    }

    /* Filtering
     */
    var sWhere = "";
    var sSearch = aoData.Where(n => n.name == "sSearch").Select(n => n.value).FirstOrDefault();
    var status = aoData.Where(n => n.name == "ddlStatus").Select(n => n.value).FirstOrDefault();
    if (sSearch != "" && aColumns.Length > 0)
    {
        sWhere = "WHERE (";
        for (int i = 0; i < aColumns.Count(); i++)
        {
            sWhere += aColumns[i] + " LIKE '%" + sSearch + "%'" + (i < aColumns.Count() - 1 ? " OR " : " ");
        }
        sWhere = sWhere.Trim() + ")";
    }

    /* Individual column filtering */
    for (int i = 0; i < aColumns.Count(); i++)
    {
        var bSearchableCol = aoData.Where(n => n.name == "bSearchable_" + i).Select(n => bool.Parse(n.value)).FirstOrDefault();
        var sSearchCol = aoData.Where(n => n.name == "sSearch_" + i).Select(n => n.value).FirstOrDefault();

        if (bSearchableCol && sSearchCol != "")
        {
            sWhere = (sWhere == "") ? "WHERE " : sWhere + " AND ";
            sWhere += aColumns[i] + " LIKE '%" + sSearchCol + "%' ";
        }

        /* Added this second if statement for my custom drop down filter on a specific column
         * The fnFilter setting with a column number does not work, and this way, ColReorder will still work
         */
        if (status != "" && aColumns[i] == "JobStatusName")
        {
            sWhere = (sWhere == "") ? "WHERE " : sWhere + " AND ";
            sWhere += aColumns[i] + " = '" + status + "' ";
        }
    }

    /* SQL queries
     * Get data to display
     */
    List<LTS.JobOverviewDynamicResult> data;
    using (var m = new Methods())
    {
        //Im not giving my SQL query
        data = m.getJobOverviewDynamicData(sWhere, sOrder, iDisplayStart, iDisplayLength);
    }

    int iFilteredTotal = 0;
    int iTotal = 0;
    if (data.Count() > 0)
    {
        /* Filtered dataset and Total dataset length */
        iFilteredTotal = (int)data.FirstOrDefault().ITotalFiltered;
        iTotal = (int)data.FirstOrDefault().ITotal;
    }

    /* Output */
    var sEcho = aoData.Where(n => n.name == "sEcho").Select(n => int.Parse(n.value)).FirstOrDefault();
    var output = new oaData<List<JobOverviewDynamic>>()
    {
        sEcho = sEcho,
        iTotalRecords = iTotal,
        iTotalDisplayRecords = iFilteredTotal,
        aaData = data.Select(n => new JobOverviewDynamic()
        {
            JobNo = (int)n.JobNo,
            JobStatusName = n.JobStatusName,
            StatusDateTime = ((DateTime)n.StatusDateTime).ToString("yyyy-MM-dd hh:mm"),
            HasAttachments = (bool)n.HasAttachments,
            Visited = (bool)n.Visited,
            Completed = (bool)n.Completed,
            JobStatusId = (int)n.JobStatusId,
            JobId = (int)n.JobId
        }).ToList(),
        sColumns = string.Join(",", aColumns)
    };

    return JsonConvert.SerializeObject(output);
}

I hope this makes somewhat sense, if not - ASK and I shall assist.