1

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

Community
  • 1
  • 1
alzambo
  • 147
  • 5
  • 19

1 Answers1

1

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?

davidkonrad
  • 83,997
  • 17
  • 205
  • 265
  • It works, thank you. Now I have anorher issue (data fetched again from disk when using pagination) but I will post it separately. – alzambo Jun 08 '15 at 10:04
  • 1
    @alzambo, why dont you do the stuff in initComplete instead? Have all the way thought it was a little bit odd solution for you to use render, you can delete the new question and I will be happy to update this answer. simply just `initComplete : function (for var i=0; .... { dettagli[meta.row] = format(data); }}` – davidkonrad Jun 08 '15 at 10:32
  • I tried: "initComplete": function( settings, json ) { for (i=0; i < settings.aoData.length; i++) { dettagli[meta.row] = format(data); } } but I cannot access `dettagli` or `meta` – alzambo Jun 08 '15 at 15:43
  • ok i think I got something: with this loop `for (i=0; i < this.api().data().length; i++) {data = this.api().row(i).data();dettagli[i] = format(data);}` i have the correct connections, but when opening child row on, say, 2nd page it will reload from file – alzambo Jun 08 '15 at 20:58
  • never mind.. I got also this one! Solved using delegated event as explained [here] http://api.jquery.com/on/ on **Direct and delegated events**. Thank you! – alzambo Jun 08 '15 at 21:41
  • 1
    @alzambo, see update. Had some other urgent things to do this evening. – davidkonrad Jun 08 '15 at 21:50