3

I'm pretty new to JS and HTML in general, so bear with me on this one.. I have a function loadData() that is called when the page load that dynamically creates an HTML table. I want to modify a few aspects of the table once it's been created (contents of the updateTable function). I tried including these modifications at then end of the loadData method, but nothing happens. However, if I move the updates out to a separate function and call this with a button click, the updates work. Even if I call updateTable at the end of loadData, it still doesn't work. I even tried appending the onLoad attribute to the table so that it would call updateTable().

I have a feeling that the reason for this behavior is because the table is not actually loaded when the updates are firing inside the loadData function itself, so the JS is trying to modify elements that don't even exist yet. However, I cannot for the life of me figure out why this would be the case if the updateTable function is being called at the end of the loadData function...

function updateTable() {
    var tbl = document.getElementById("dataTable");
    var rows = document.getElementsByTagName("tr");
    maxCols = 0;
    for ( var i = 1; i < rows.length; i++ ) {
      var cols = rows[i].cells.length; 
      if ( cols > maxCols ){
        maxCols = cols;
      }
    }
    headerCols = rows[0].cells.length; 
    diff = maxCols - headerCols + 1; 
    tbl.rows[0].cells[3].colSpan = diff;
    tbl.rows[0].cells[3].align = "center";

    for ( var i = 1; i < rows.length; i++ ) {
      var cols = rows[i].cells.length;
      for (var a=cols; a < maxCols; a++){
        rows[i].insertCell(a);
      }
    }
    //console.log(maxCols); 
}

function loadData() {

    d3.text("data.csv", function(data) {
        var parsedCSV = d3.csv.parseRows(data);
        var container = d3.select('#contTable');
           .append("table").attr('class','table').attr('id','dataTable')

        .selectAll("tr")
            .data(parsedCSV).enter()
            .append("tr")

        .selectAll("td")
            .data(function(d) {
                return d;
            }).enter()
            .append("td")
            .text(function(d) {
                return d;
            });
    });
}

Any insight would be appreciated.

Thanks!

1 Answers1

1

In the code you posted, updateTable isn't called at all. This answer assumes your observed behavior happens when you call updateTable at the very end of loadData, outside the d3.text callback.

Move the call to updateTable to the end of the d3.text callback, so it gets run immediately after #dataTable has been set up.

Your suspicion is correct. d3.text loads data.csv asynchronously, so the code that creates #dataTable doesn't get run until after the browser's retrieved data.csv. Meanwhile, the rest of loadData keeps right on going. It hits updateTable, but since the engine hasn't had the chance to run the d3.text callback yet, there's no #dataTable to operate on.

For more on Javascript's asynchronicity, see this answer.

AuxTaco
  • 4,883
  • 1
  • 12
  • 27
  • Thanks, AuxTaco! I moved updateTable to inside the d3.text callback and it worked! This concept of sync/async processing is a bit foreign to me as all the bash/python scripting I'm familiar with is executed synchronously unless specified otherwise.. I'll have to do some reading on asynchronicity. Thanks again! – Chris LaMendola Dec 24 '17 at 23:34