alzambo
alzambo

Reputation: 147

datatables - preload data to array via ajax performs multiple connections

following this tutorial I ended up with this code (that basically loads the child row content from an external file, parsed with JsRender, to an array) :

/* Formatting function for row details - modify as you need */
function format ( d ) {
    // `d` is the original data object for the row
    // carica il template del dettaglio
    $.ajax ({
        async: false,
        type: "POST",
        url: "incaricodetail.html",
        cache: false,
        success: function(data){
            templateHtml = data; 
        }
    });
    var template = $.templates(templateHtml);
    var htmlOutput = template.render(d);

    return htmlOutput;
}

$(document).ready(function() {

    $.fn.dataTable.moment( 'DD/MM/YYYY' ); 
    var dettagli = []; 
    var table = $('#tabellaDati').DataTable( {
        "data": <?= json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));?>,  
        "columns": [
            {
                "className":      'details-control',
                "orderable":      false,
                "data":           null,
                "defaultContent":
                    '<a class="btn btn-xs" href="incarico_edit.php?id=<?=$id;?>&pageFrom=<?=pathinfo($_SERVER['PHP_SELF'], PATHINFO_FILENAME ); ?>" title="Modifica"><span class="glyphicon glyphicon-edit"></span></a>'+
                    '<a class="btn btn-xs delete-object" href="delete.php?id=<?=$row["id"]?>" delete-id="{$id}"" title="Elimina"><span class="glyphicon glyphicon-trash"></span></a>'+
                    '<a class="btn btn-xs" href="#" id="mostraDettaglio" title="dettaglio"><span class="glyphicon glyphicon-plus"></span></a>',
                    "render": function(data, type, row, meta) {
                        dettagli[meta.row] = format(data);
                    }

           },
           { "data": "id" },
           { "data": "protocollo" },
           { 
              "data": "dataIncarico",
              "type": "date",
              "dateFormat": "dd-mm-yyyy"
           }

        ],
        "order": [[1, 'asc']]
    });

    // Add event listener for opening and closing details
    $('#tabellaDati tbody #mostraDettaglio').on('click', function () {
        var tr = $(this).closest('tr');
        var row = table.row( tr );

        if ( row.child.isShown() ) {
            // This row is already open - close it
            row.child.hide();
            tr.removeClass('shown');
        }
        else {
            // Open this row
            row.child(dettagli[row.index()]).show();
            tr.addClass('shown');
        }
    } );
} );

I don't know why, but the ajax call to the file incaricodetail.html is done three times (example, for two records I got 6 POST connections).

DataTables Debugger code: onucak

Whay could it be? Alex

Upvotes: 1

Views: 1074

Answers (1)

davidkonrad
davidkonrad

Reputation: 85558

Upon initialization, render is called on several occasions :

  • display
  • sort
  • filter
  • type (detection)

That is for each row! You can check the type of the render call through the type argument. A qualified guess is that your render function is called on type, display and filter - you have 2 rows, it gives 6 calls to the format() function, and by that 6 POST connections since you have turned cache off.

You can avoid that by simply :

render: function(data, type, row, meta) {
   if (typeof dettagli[meta.row] == 'undefined') {
      dettagli[meta.row] = format(data);
   }
}

Why is render called multiple times with different type?
So you can return different data for different purposes. Lets say you have some HTML containing a checkbox as display, for sort you can pass 0, for filtering you can pass yes / no, for type you can pass number.


Update. initialise dettagli[] in initComplete() instead of render() :

var table = $('#example').DataTable({
    initComplete : function() {
        var api = this.api(),
            rowCount = api.data().length;
        for (var i=0;i<rowCount;i++) {
            dettagli[i] = format(api.row(i).data()[0]);
        }    
    }        
});

This should do the same as dettagli[meta.row] = format(data);, i.e call format() with the content of column #0 for each row.

You should also consider loading incaricodetail.html only once. Why load it over and over each time? It does not seem that the content of incaricodetail.html is meant to change, so would

var template;
$.get("incaricodetail.html", function(html) {
   template = $.templates(html);
});

function format ( d ) {
   return template.render(d);
}

not do exactly the same?

Upvotes: 1

Related Questions