0

EDIT: With significant help from others, I was able to work up a solution.

I'm taking data from a Google Spreadsheet and then attempting to render it as an HTML table in a WebApp.

I'd like the data to show up like

<tr> <td> <td> <td>

exactly how it looks in a spreadsheet, with each value in a separate cell.

enter image description here

Big picture, I'd like to be able to do different things to each <td>, so I want to make sure I structure the data in a usable way.

Code.GS

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function webAppTest() {
   getTeamArray();
} 


function getTeamArray() {

  var ss = SpreadsheetApp.getActive();
  var sheet = ss.getSheetByName('Sheet1');
  var range = sheet.getRange('A2:H1000');
  var values = range.getValues();
  //Logger.log(values);


  var teamsArray = [];

  for (var i = 0; i < values.length; ++i) {

   var column = values[i];
    var colA = column[0];
    var colB = column[1];           
    var colC = column[2];           
    var colD = column[3];           
    var colE = column[4];          
    var colF = column[5];
    var colG = column[6];
    var colH = column[7];

if (colA != '') {

teamsArray.push(values[i][0]);
teamsArray.push(values[i][3]);
teamsArray.push(values[i][4]);
}
} 


  var array2 = [];
    while(teamsArray.length) array2.push(teamsArray.splice(0,3));
      var lengthDivName2 = array2.length;
      var widthDivName2 = array2[0].length;

//Logger.log(teamsArray);
Logger.log(array2);
//return teamsArray;
return array2;


}

Index.HTML Function

 function buildOptionsList(teamsArray) {
        var div = document.getElementById('myList');
          for (var i = 0; i < teamsArray.length; i++) {
            var tr = document.createElement('tr');
            var td = document.createElement('td');
            var cLass = td.setAttribute('class','ui-state-default');
            var iD = td.setAttribute('id',teamsArray[i]);


        td.appendChild(document.createTextNode(teamsArray[i]));
        div.appendChild(tr);
        div.appendChild(td);
          }
       }


</script>

 </head>
  <body>
    <div id="myList" class="connectedSortable">MY LIST</div>
 </body>
</html>

ATTEMPT 1

enter image description here

ATTEMPT 2

I tried to change the array creation in code.gs which got all the correct data in the <tr> but didn't split into <td>s

enter image description here

TheMaster
  • 45,448
  • 6
  • 62
  • 85
N.O.Davis
  • 501
  • 2
  • 10
  • 22
  • In order to correctly understand about your question, can you provide the sample input data and the output you want? I think that such information will help users think of your solution. – Tanaike Jan 16 '19 at 23:20
  • I actually prefer doing things like this on the server side. Take a look at [this example](https://stackoverflow.com/a/54207155/7215091) that I did yesterday. – Cooper Jan 16 '19 at 23:38
  • The expected output is above. "I'd like it to show up like..." So each CSV is its own ``. I can add where `teamsArray` comes from. – N.O.Davis Jan 17 '19 at 00:00
  • Updated. Thanks! – N.O.Davis Jan 17 '19 at 00:08
  • Cooper, I did try creating the HTML on the server side but nothing was actually returned by the HTML. I took what you had done and applied my own variables. – N.O.Davis Jan 17 '19 at 04:29
  • @N.O.Davis Thank you for updating. I would like to confirm whether I could understand about your question. You want to put a table using the returned values as the image that you show in your question. Is my understanding correct? – Tanaike Jan 17 '19 at 05:26
  • Yep that's correct. – N.O.Davis Jan 17 '19 at 18:41
  • @N.O.Davis Thank you for replying. I noticed that several answers have been posted. I think that they will resolve your issue. – Tanaike Jan 17 '19 at 23:52
  • I found a solution that worked for me with further research, thanks for your help! – N.O.Davis Jan 18 '19 at 03:09

3 Answers3

1

I am not sure I understood the way you receive the data, but if teamsArray contain information about one line the solution would be something like this:

function buildOptionsList(teamsArray) {
    var div = document.getElementById('myList');
    var tr = document.createElement('tr');
    for (var i = 0; i < teamsArray.length; i++) {
        var td = document.createElement('td');
        var cLass = td.setAttribute('class','ui-state-default');
        var iD = td.setAttribute('id',teamsArray[i]);

        td.appendChild(document.createTextNode(teamsArray[i]));
        tr.appendChild(td);
    }
    div.appendChild(tr);
}
Blue
  • 355
  • 1
  • 9
  • Thanks! I'll check this out once I get home. I updated the question to include the source of the array. I originally left it out so I wasn't cluttering up my question. – N.O.Davis Jan 17 '19 at 00:02
  • 1
    I found a solution that worked for me with further research, thanks for your help! – N.O.Davis Jan 18 '19 at 03:08
1

Use Array#map, Array#reduce, and Array#join to surround the elements of the inner array with the required HTML tags and then condense to a single string. Currently you have an implicit Array#toString call which creates a comma-separated string of the inner array's elements (the inner array is at teamData[i]), and thus you only have a single cell in your previous attempts' output.

This simple function assumes you aren't applying any column- or row-specific styles or attributes, so it can simply treat every <td> element equivalently. If you have symmetric styling to apply, you would want to process the headers/row variables with .map first (since you can then use the elements' indices) and then .join("") instead of just .join using the tag delimiters.

function getTableHTMLFrom(array, hasHeaders) {
  if (!array || !array.length || !array[0].length)
    return "";

  const headerString = (hasHeaders ?
    "<tr><th>" + array.shift().join("</th><th>") + "</th></tr>"
    : "");

  const tdTag = "<td class=\"ui-state-default\">";
  const bodyString = array.reduce(function (s, row) {
    s += "<tr>" + tdTag + row.join("</td>" + tdTag) + "</td></tr>";
    return s;
  }, "");
  return "<table>" + headerString + bodyString + "</table>";
}
tehhowch
  • 9,645
  • 4
  • 24
  • 42
  • I applied this to `Index.HTML` and changed out the variables/function name, but nothing showed up in the WebApp. Did I need to return this to Code.GS? `array2` has values in Code.GS. – N.O.Davis Jan 17 '19 at 18:56
  • This hypothetical function `getTableHTMLFrom` would be used to obtain the HTML string needed by [`HTMLElement#innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) – tehhowch Jan 17 '19 at 23:20
  • I found a solution that worked for me with further research, thanks for your help! – N.O.Davis Jan 18 '19 at 03:08
0

I found a solution (applied to Index.HTML) that worked based on THIS.

function buildOptionsList(array2) {
  var table = document.createElement('table');
  var tableBody = document.createElement('tbody');

  array2.forEach(function(rowData) {
    var row = document.createElement('tr');

    rowData.forEach(function(cellData) {
      var cell = document.createElement('td');
      var cLass = td.setAttribute('class','ui-state-default');
      cell.appendChild(document.createTextNode(cellData));
      row.appendChild(cell);
    });

    tableBody.appendChild(row);
  });

  table.appendChild(tableBody);
  document.body.appendChild(table);
}

buildOptionsList(array2);
N.O.Davis
  • 501
  • 2
  • 10
  • 22