EDITOR- Traversing table's data once initilized or updated

EDITOR- Traversing table's data once initilized or updated

agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
edited June 2012 in General
Hello,
I'm creating a series of tables with Editor, which work perfectly. However, I'd like to be able to traverse through each row (in a specific column) in a certain table, add up each value and reflect the total in another place of my page.

I tried to follow the example for "fnFooterCallback" found at the examples section, however it's giving me the following error: "DataTables warning (table id = 'inc_items_short'): Cannot reinitialise DataTable." if I use any of the call back functions (because the table has been already created and displayed)

If using Editor, What would be the right approach to capture any change on the table's data and reflect something accordingly?

Thanks in advance

Replies

  • allanallan Posts: 63,540Questions: 1Answers: 10,476 Site admin
    Hi,

    Glad to hear that you are enjoying using Editor thus far :-)

    I think using Editor should actually make little difference to how the column sum is done - you are right in using fnFooterCallback (or fnDrawCallback), but it sounds like your are trying to reinitialise the DataTables.

    What I would suggest is using the http://datatables.net/plug-ins/api#fnGetColumnData plug-in in fnFooterCallback (just call this.fnGetColumnData(...)) and then sum the array if gives you back :-)

    Allan
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Thanks Allan, I was able to get table's data by using that function and traverse through it.

    However, now I'm facing this issue that ONLY if I DO leave the alert sentence there -see code extract, it traverses correctly and gathers the whole data.
    But if I remove that sentence (which I need to), it doesn't gets any data from the table,, like if it was empty (even the actual CRUD table shows rows data as expected.
    Not sure if it has to do with the obtrusive/non-ubtrusive model, with the time with the data is actually populated (and displayed) in the CRUD table view, or what else.

    I thought $document).ready was executed as the very last instruction after everything else has been processed.

    Can you guide on this, or should I look into a different forum? Not sure if this behavior is related with DataTables Editor or is a more basic event handling thing

    Code snipet:


    $(document).ready( function() {
    var dataTable = $('#inc_items').dataTable();

    alert(dataTable);


    var aoData = dataTable.fnGetData();
    var recipientList = new CategoryCollection();
    // Loop over each value in the array.
    $.each(aoData, function(intIndex, objRow){
    if (recipientList.exists(objRow.recipient, objRow.category)) {
    recipientList.increase(objRow.recipient, objRow.category, objRow.payment_amount);
    console.debug("UPDATE - Recipient: " + objRow.recipient + " | Category: " + objRow.category + " | Amount: " + objRow.payment_amount);
    } else{
    recipientList.insert(objRow.recipient, objRow.category, objRow.payment_amount);
    console.debug("NEW - Recipient: " + objRow.recipient + " | Category: " + objRow.category + " | Amount: " + objRow.payment_amount);
    }
    });
    recipientList.print();
    } );
  • allanallan Posts: 63,540Questions: 1Answers: 10,476 Site admin
    I doubt that this is directly related to Editor, but it does sounds like integration with DataTables - so I should be able to help :-).

    If you could link me to your page that would be really helpful (a page showing the problem you are having).

    Allan
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Thanks Allan,
    This page is still on my local environment, and I'm afraid pasting the code here will make it too large.
    Let me know if there is a place to upload it or if you want me to past the ~1000 lines here
  • allanallan Posts: 63,540Questions: 1Answers: 10,476 Site admin
    http://live.datatables.net will allow you to create a live working example on the web (rather like JSFiddle).

    Allan
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Hello,
    I'm trying to replicate my code into the live.datatables.net.

    Mean time I'm attaching a functional extract of my whole code, please notice that:

    1) if I enable both alerts ( alert("Income OK"); and alert("CC Expenses OK"); ), only the first one is displayed and only the INCOME summary table (on dashboard tab) is populated.
    2) If I disable the "Income OK" alert, and the "CC Expenses OK" alert is left enabled, then only the "EXPENSES" summary table is populated in the Dashboard tab.
    3) If I disable both nothing is written to the INCOME nor to the EXPENSES tables.

    Hope you can provide some guidance.





    @import "css/demo_page.css";
    @import "css/jquery.dataTables.css";
    @import "css/dataTables.tabletools.css";
    @import "css/dataTables.editor.css";



    @import "css/demo_table.css";
    @import "css/jquery-ui.css";



    <!-- Load the tabber code -->














    document.write('.tabber{display:none;}<\/style>');

    var tabberOptions = {

    'manualStartup':true,


    'onLoad': function(argsObj) {
    if (argsObj.tabber.id == 'demotab') {
    alert('Finished loading demotab!');
    }
    },

    'onClick': function(argsObj) {

    var t = argsObj.tabber;
    var id = t.id;
    var i = argsObj.index;
    var e = argsObj.event;

    if (id == 'demotab') {
    return confirm('Swtich to '+t.tabs[i].headingText+'?\nEvent type: '+e.type);
    }

    if (t.tabs[i].headingText == 'Dashboard') {
    $("#income_by_category").val($("#totalAmount").val());
    }


    },


    'addLinkId': true

    };





    $(document).ready( function() {

    var dataTable = $('#inc_items').dataTable();
    //alert("Income OK");
    var aoData = dataTable.fnGetData();
    var incomeList = new CategoryCollection();

    var fGrossIncome = 0.0;
    var type = "Gross Income";
    $.each(aoData, function(intIndex, objRow){
    if (incomeList.exists(objRow.recipient, type, objRow.category)) {
    fGrossIncome += parseFloat(objRow.payment_amount);
    incomeList.increase(objRow.recipient, type, objRow.category, objRow.payment_amount);

    } else{
    fGrossIncome += parseFloat(objRow.payment_amount);
    incomeList.insert(objRow.recipient, type, objRow.category, objRow.payment_amount);

    }
    });

    var totalAmount = parseFloat(0.0);
    incomeList.forEach( function(objItem) {
    totalAmount += parseFloat(objItem.amount);
    $("#income_summary > tbody").append(""+ objItem.name + "" +
    ""+ type + "" +
    ""+ objItem.category + "" +
    ""+ objItem.amount + "" +
    "");
    });

    $("#income_summary > tbody").append("TOTAL:"+ totalAmount + "");


    var ccDataTable = $('#exp_credit_cards').dataTable();
    //alert("CC Expenses OK");
    var aoData = ccDataTable.fnGetData();
    var expenseList = new CategoryCollection();
    var fCreditCards = 0.0;
    var type = "Credit Cards";
    var category = "Credit Cards";
    $.each(aoData, function(intIndex, objRow){
    if (expenseList.exists(objRow.debtor, type, category)) {
    fCreditCards += parseFloat(objRow.payment_amount);
    expenseList.increase(objRow.debtor, type, category, objRow.payment_amount);
    } else{
    fCreditCards += parseFloat(objRow.payment_amount);
    expenseList.insert(objRow.debtor, type, category, objRow.payment_amount);
    }
    });
    var totalCCAmount = parseFloat(0.0);
    expenseList.forEach( function(objItem) {
    totalCCAmount += parseFloat(objItem.amount);
    $("#expense_summary > tbody").append(""+ objItem.name + "" +
    ""+ type + "" +
    ""+ objItem.category + "" +
    ""+ objItem.amount + "" +
    "");
    });
    $("#expense_summary > tbody").append("TOTAL:"+ totalCCAmount + "");
    } );









    Dashboard




    Income




    Name
    Type
    Category
    Total











    Middle Col







    Expenses




    Debtor
    Type
    category
    Total









     







    Income


    Monthly Income




    From/To
    Recipient
    Category
    Amount
    Estimated?
    Periodicity
    Next Discount Date
    Automatic Tracking
    Bill Reminder
    Recipient ID
    Family linked
    Income Type
    Memo










    Monthly Expenses


    Credit Cards




    Bank
    Debtor Name
    Credit Card Name
    Credit Limit
    Current Balance
    Interest Rate
    Debtor ID
    Min. Payment
    To Capital
    To Interest
    Due Date
    Bill Reminder
    Family Linked
    Automatic Tracking
    Memo
    Min Rate (%)
    Cut date
    Associated Promotions?
    Total Promotions ($)













    tabberAutomatic(tabberOptions);
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Hi Allan,
    I tried to replicate my code as suggested on "http://live.datatables.net", unfortunately I wasn't able to, because the references to other libraries.
    Please let me know if by looking at the code I attached above helps to delve into what's happening, otherwise I'll start working on uploading this code into a live server.
    Thanks again
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Hi Allan,
    I uploaded the app to a live site: http://a4enterprise.com/tabber/financial_dashboard.html
    However, It continues without working, now It's giving me also the error: DataTables warning: JSON data from server could not be parsed.
    I tested the connection with a simple script (http://a4enterprise.com/tabber/connection/connection.php), the connection to the DB is being gathered successfully, but no luck when calling the Datatables script.
    I've looked into Firebug, but isn't showing anything.

    I uploaded into Datatables Debug (debug code: icuhav ), where is triggering the error:
    Fatal error
    Call to undefined function date_create_from_format()
    DTFormat.class.php on line 35.

    Hope you can provide guidance here
  • allanallan Posts: 63,540Questions: 1Answers: 10,476 Site admin
    date_create_from_format is a function which is introduced to PHP in v5.3, so my guess is that you are running an old version of PHP on your server ( http://uk.php.net/date_create_from_format ).

    I think you need to either update your PHP install to 5.3 or the current 5.4, or the function date_create_from_format needs to be replaced with something that will work with older versions of PHP.

    Allan
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Hi Allan,
    I removed the "date_create" error and setup a new test page:
    http://a4enterprise.com/tabber/temp.html.

    The same behavior remains, if I remove the sentence "alert("TEST");" the script doesn't seem to get anything via dataTable() and displays nothing.
    But if I display the alert, everything works just fine and the records from the Datatable are traversed correctly.

    The code on the above link is very simplified now, just to prove the issue. Hope this time we can get to something, whether it's an integration issue or if I'm doing something wrong.
    Thanks for your support
  • allanallan Posts: 63,540Questions: 1Answers: 10,476 Site admin
    Okay - I think I understand now - you have:

    [code]
    $(document).ready( function() {
    var dtObj = $('#test').dataTable();
    var aoData = dtObj.fnGetData();
    [...]
    [/code]

    that will run only when the page is first loaded, and since you are loading the data for the DataTable through Ajax (i.e. it is asynchronous) this code will run before the data has been loaded.

    It works with an alert in there, since that is blocking and allowing the Ajax request to complete.

    So I'd suggest using fnFooterCallback as I suggested to calculate your column sum. That will be calculated on every draw - see for example: http://datatables.net/release-datatables/examples/advanced_init/footer_callback.html

    Allan
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Thanks Allan,
    I didn't decide to use the fnFooterCallback approach because it was giving me an error like shown below, which I didn't understand how to address.
    As per your suggestion, I just changed the code to include fnFooterCallback, but it keeps triggering the cannot reinitialize error.

    "
    Datatables warning (table id = 'test'): Cannot reinitialise DataTable.
    To retrieve the Datatables object for this table, pass no arguments or see the docs for bRetrieve and bDestroy
    "

    You can see the code at: http://a4enterprise.com/tabber/temp2.html
  • allanallan Posts: 63,540Questions: 1Answers: 10,476 Site admin
    Hi,

    I'm not entirely sure how where the fnFooterCallback code is on that page - I don't actually see any DataTables on it. However, my guess is that (like the error says) you are trying to initialise the DataTables twice with different parameters. You can only initialise a table once - so your footer callback code needs to go in with the rest of your table configuration.

    Allan
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Thank Allan, Now I got your point.
    The call to fnFooterCallback is on the Editor's generated table.test.js, I customized that call and it's gathering the table's data after it's populated (which is correct).

    Based on your feedback, I realized that I'm pursuing for something different: What I need is to gather the data from "aaData" (from 8-10 Datatables I have on the same page), do some operations and write it to separate "regular" html summary tables, which can be defined either prior or after the Datatables have been populated.
    I'm not too familiar with the Asynchronous/Synchronous model of Javascript, so I guess my problem reduces to that.
    If you have any example or can provide any guidance on how to accomplish this, I'd appreciate it.
    Otherwise I thank you again for your support you have provided here.
  • allanallan Posts: 63,540Questions: 1Answers: 10,476 Site admin
    I still think fnFooterCallback is the way to go. My example (linked above) shows how you can sum an column - then you have that information and you can do anything you want with it.

    > If you have any example or can provide any guidance on how to accomplish this

    Yes have a close look at my example fnFooterCallback :-)

    Allan
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Hi Allan,
    I think I haven't been able to explain what I'm pursuing here, or to understand how to use your example

    1) I have two files:
    a)table.test.js -> which was generated by Editor (and calls the other auto-generated Editor files)
    b)test2.html -> Includes .js file and a call to the Datatable table
    2) I define a global variable in test2.html object called hashSavings = new Hashtable()
    3) If I include the "fnFooterCallback" call and example code in the .js file, it gathers the rows' data and put it into my object (savingsHash), no issues here since I can travers what was put there
    4) But, If I try to traverse the same object in the main html, it's size is shown as 0, and no actual data seems to be stored there.
    5) I understand the data is being stored, so we go back to the sync/async thing, because if I display the alert() again just before trying to traverse the object (in the .html), I can get the data that was put in it during the call to the "fnFooterCallback"
  • allanallan Posts: 63,540Questions: 1Answers: 10,476 Site admin
    Okay this is what I would suggest:

    1. Alter table.test.js to include an fnFooterCallback function such as this in the DataTables initialisation:

    [code]
    "fnFooterCallback": function () {
    console.log("footer callback");
    }
    [/code]

    2. Check that on your browser's Javascript console you see the text "footer callback" appear for every draw.

    3. Pick up the fnGetColumnData plug-in I mentioned before from the plug-ins page.

    4. Use fnGetColumnData (this.fnGetColumnData(...) inside the callback) in the fnFooterCallback function to get an array of data for the column you want.

    5. Loop over the data array, sum and write the sum to the footer's cells as required.

    Allan
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Thanks Allan,
    That part is working fine, what I haven't accomplished yet, it the second part of my needs, which somehow I described above:
    I have several Datatables in my page, and I need them all to be loaded and do some post-processing after loading (or changing).
    With the objects generated during each datatable´s summarization, I'm trying to build up a dashboard.

    My issue is that the standard tables used in the Dashboard, are being built before all the Datatables finish their own processing, but I don't think this has anything to do with Datatables, but with the sync/async that I still need to delve into.

    thanks for your support
  • allanallan Posts: 63,540Questions: 1Answers: 10,476 Site admin
    So there are a number of options to process data in DataTables:

    1. Use fnServerData to intercept the Ajax call and manipulate the data that is returned from the server before DataTables does its thing with it.

    2. Use mDataProp as a function to manipulate the data for each row - http://datatables.net/blog/Orthogonal_data

    3. Use fnRender for simple manipulation of column data (making HTML links etc). A bit like mDataProp as a function, but less flexible.

    Allan
  • agustin_garciaagustin_garcia Posts: 17Questions: 0Answers: 0
    Thanks Allan, inserting fnServerData at the end of the $('#example').dataTable( { ....}); function made the trick.

    I just added my fnServerData code after the oTableTools section generated by EDITOR, it was somehting like this:

    $('#example').dataTable( {
    ...
    ...
    "oTableTools": {
    "sRowSelect": "single",
    "aButtons": [
    { "sExtends": "editor_create", "editor": editor },
    { "sExtends": "editor_edit", "editor": editor },
    { "sExtends": "editor_remove", "editor": editor }
    ]
    },
    "fnServerData": function ( sSource, aoData, fnCallback ) {
    $.getJSON( sSource, aoData, function (json) {
    /* My code*/
    $.each(json.aaData, function(intIndex, objRow){
    insertSummaryRecord(...);
    });

    fnCallback(json);
    } );
    } );
This discussion has been closed.