Modifying Cell Value Within init.dt

Modifying Cell Value Within init.dt

anthony89anthony89 Posts: 26Questions: 8Answers: 0

I am having an issue trying to modify cell values after Datatables finishes loading data. Here's an excerpt from my defining of Datatables.

var oQueueTable = $('#queue_table').on( 'init.dt', function () {
        eta();
    })
    .DataTable( {
        paging: false,
        info: false,
        searching: false,
        rowReorder: {
            dataSrc: "sortID"
        },
        processing: true,
        serverSide: true,
        ajax: root + "resources/php/data_handler.php",
        // use createdrow to add record id field to the tr id
        "createdRow": function( row, data, dataIndex ) {
            $(row).attr('id', data.id);
        },
        columns: [
            { // More details column
                className: 'eta',
                title: 'ETA',
                orderable: false,
                data: null,
                defaultContent: ""
            },

I call the custom function eta() which is to manually populate the first column with a calculated value. The values get calculated, but when I load the page, the custom value flashed briefly but then disappears. Custom function is:

    function eta() {
        $.get(root + "resources/nowplaying.txt", function(response) {
            obj = JSON.parse(response);
            obj = obj[0];
            remaining_time(obj.date_played, obj.duration, function(current_duration) {
                $.get(root + "resources/php/server_date_time.php", function(response) {
                    oQueueTable
                        .rows()
                        .every(function (rowIdx, tableLoop, rowLoop) {
                        var duration = oQueueTable.cell(rowIdx,6).data();
                        var eta = "";
                        var obj = "";
                        if (rowIdx == 0) {
                            var date = new Date(response);

                            var tmp = parseInt(current_duration);
                            var minutesToAdd = Math.floor(tmp / 60000);
                            var secondsToAdd = ((tmp % 60000) / 1000);

                            date.setMinutes(date.getMinutes() + minutesToAdd);
                            date.setSeconds(date.getSeconds() + secondsToAdd);

                            var h = date.getHours();
                            var m = date.getMinutes();
                            var s = date.getSeconds();
                            eta = h + ":" + m + ":" + s;
                            console.log("eta: " + eta);
                            console.log("rowIdx: " + rowIdx);
                            oQueueTable.cell(rowIdx,0).data(eta).draw();
                        }
                        var eta = oQueueTable.cell(rowIdx,6).data();
                    });
                });

            });
        });
    }

How can I insure that I can populate the first column with my calculated values after the table fully loads data and is finished drawing?

Thanks.

This question has an accepted answers - jump to answer

Answers

  • kthorngrenkthorngren Posts: 21,147Questions: 26Answers: 4,918

    How can I insure that I can populate the first column with my calculated values after the table fully loads data and is finished drawing?

    You are using server side processing and calling draw() in line 29 (oQueueTable.cell(rowIdx,0).data(eta).draw();) which uses the server side processing process to draw the table.

    I see you are fetching info from the server to build the timestamp for the column. Can you just do this calculation in your server script for the original response? Or maybe provide the server time in the row data and use columns.render to perform the calculation.

    Kevin

  • anthony89anthony89 Posts: 26Questions: 8Answers: 0

    I initially attempted to use the columns.render option but was not fully satisfied with the result. The first column in my oQueueTable Datatables object is a calculated field to determine the estimated time of airing (eta) of a given track in the queue table. The server side processing grabs those records, which include a duration field in milliseconds, so I am attempting to set the eta of the first column to be the server time plus track duration.

    The subsequent eta columns must just add their duration to the previous row's eta column.

    Perhaps I can rethink the process again.

    So, when doing server side processing, is there a way to modify that data and then show in the table without calling the .draw() event?

  • anthony89anthony89 Posts: 26Questions: 8Answers: 0

    I tried again to use the columns.render option, but Datatables runs through loading basically before the code inside the render completes because those inside functions have to complete. Any suggestions?

    columns: [
                { // More details column
                    className: 'eta',
                    title: 'ETA',
                    orderable: false,
                    data: 'duration',
                    defaultContent: "",
                    render( data, type, row, meta ) {
                        console.log("meta.row: " + meta.row);
                        $.get(root + "resources/nowplaying.txt", function(response) {
                            obj = JSON.parse(response);
                            obj = obj[0];
                            remaining_time(obj.date_played, obj.duration, function(current_duration) {
                                if (meta.row == 0) {
                                    var date = new Date(row['servertime']);
                                    console.log("date: " + date);
                                    var tmp = parseInt(current_duration);
                                    var minutesToAdd = Math.floor(tmp / 60000);
                                    var secondsToAdd = ((tmp % 60000) / 1000);
    
                                    date.setMinutes(date.getMinutes() + minutesToAdd);
                                    date.setSeconds(date.getSeconds() + secondsToAdd);
    
                                    var h = date.getHours();
                                    var m = date.getMinutes();
                                    var s = date.getSeconds();
                                    var eta = h + ":" + m + ":" + s;
                                    console.log("eta: " + eta);
                                    return eta;
                                }
    
                            });
                        });
                    }
                },
    
  • kthorngrenkthorngren Posts: 21,147Questions: 26Answers: 4,918

    Its not recommended to use ajax requests in columns.render. In the first code snippet you usedresources/php/server_date_time.php. In the-option columns.renderyou usedresources/nowplaying.txt`. Is the goal just to get a reference time from the server? If so maybe you cane do something like this pseudo code:

    $.get(root + "resources/php/server_date_time.php", function(response) {
      
      //  Initialize datatables
      // In columns.render use the `response` datetime for the calculation
    
    });
    

    Basically fetch the server data you need to build the table. Then in the Ajax callback init Datatables and use that fetched data for your calculations.

    Kevinn

  • anthony89anthony89 Posts: 26Questions: 8Answers: 0
    edited August 2020

    Server time is just one aspect. I can get it through ajax call or as you mentioned by way of the original response. The issue is, I need to know how much time is left in track that is currently playing.

    I determine that by grabbing the data from nowplaying.txt which reports date/time the current track began to air. Using

    remaining_time(obj.date_played, obj.duration, function(current_duration)
    

    I calc how much time is remaining on current track which then becomes part of the calculation to determine when row 1 track is estimated to air (eta), and all subsequent rows (tracks in queue) will then be scheduled to air.

    This is sort of the reason I thought about just calling a function after Datatables completes it loading, but I had the problem with the .draw only very briefly showing the calculate value.

  • kthorngrenkthorngren Posts: 21,147Questions: 26Answers: 4,918
    Answer ✓

    The init event and initComplete are essentially the same thing. They run after Datatables has finished initializing. With server side processing init will only run once for the first page.

    It sounds like you will want to use either draw or drawCallback for this. You may be able to use the same code you have in the init event. Although you definitely don't want to call draw() in either of these events as it. will cause an infinite loop. Try oQueueTable.cell(rowIdx,0).data(eta).draw(); without calling draw, ie, oQueueTable.cell(rowIdx,0).data(eta);. Is the table data updated? I don't remember off the top of my head if the table will show the updated data.

    I may be able to put a simple demo together tomorrow if you still have questions.

    Kevin

  • anthony89anthony89 Posts: 26Questions: 8Answers: 0

    Moving the code to drawCallback seems to be working as I need it to.

    Thanks.

This discussion has been closed.