Nessi
Nessi

Reputation: 286

How to export a table with input fields using JavaScript?

The table is like this:

<table id="sample_table">
  <tr>
   <td>1</td>
   <td><input type="text" size="5" id="in2" name="txt2" value="0"/></td>
   <td><input type="text" size="5" id="in3" name="txt3" value="0"/></td>
   <td><input type="text" size="5" id="in4" name="txt4" value="0"/></td>
 </tr>

the js code is like this:

function export(filename) {
    var csv = [];
    var rows = document.getElementById('tbl_posts').querySelectorAll("table tr");

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

        var row = [], cols = rows[i].querySelectorAll("td, th");
    
        for (var j = 0; j < cols.length; j++){
            row.push(cols[j].innerText);
        }
            
        csv.push(row.join(","));

}

// Download CSV file not posted here
downloadCSV(csv.join("\n"), filename);
}

and the export button:

<button type="button" onclick="export('myFile')">Export</button>

since it reads td not input fields it adds empty '' strings into csv list. How can I access inputs and push them into row list?

Upvotes: 3

Views: 1106

Answers (5)

giulp
giulp

Reputation: 2408

Just a variation on @Aaron's answer, giulp's way :)
... using .map is definitely the way I'd choose, more concise, less error prone, see @Ifaruki's answer for yet another path in this direction

function fetchData(filename) {
  let cells = document.querySelectorAll("table#sample_table tr td");
  // using map over a NodeList -> see below 
  var csv = Array.prototype.map.call(cells, function(cell){
       // if the first is undefined (falsey in js)
       // then return the second, a widely used pattern
       return cell.firstChild.value || cell.innerText;  
  }).join(",");
  console.log(csv);
}
<table id="sample_table">
  <tr>
    <td>1</td>
    <td><input type="text" size="5" id="in2" name="txt2" value="0" /></td>
    <td><input type="text" size="5" id="in3" name="txt3" value="0" /></td>
    <td><input type="text" size="5" id="in4" name="txt4" value="0" /></td>
  </tr>
</table>
<button type="button" onclick="fetchData('myFile')">Export</button>

MDN Array.prototype.map

Upvotes: 0

Ilijanovic
Ilijanovic

Reputation: 14904

You could also go with Array.from and map it

function fetchData() {
   let data = Array.from(document.querySelectorAll("#sample_table td"))
      .map(el => el.firstChild.value || el.innerText)
      .join(",");
  
   console.log(data);
}
<table id="sample_table">
  <tr>
   <td>1</td>
   <td><input type="text" size="5" id="in2" name="txt2" value="0"/></td>
   <td><input type="text" size="5" id="in3" name="txt3" value="0"/></td>
   <td><input type="text" size="5" id="in4" name="txt4" value="0"/></td>
   <button onclick="fetchData()">Fetch</button>
 </tr>

Upvotes: 2

Netham
Netham

Reputation: 1178

I saw your comments. If we seek a solution by minimum editing to your code and also I don't know the rest of the document structure, then this will work for multiple rows.

The basic idea is when you already have a table row, then all you need is inputs inside them. So we seek inputs and then go on them one by one.

function exportF(filename) {
var csv = [];
var rows = document.getElementById('sample_table').querySelectorAll("table tr");

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

    var row = [], cols = rows[i].querySelectorAll("input");

    for (var j = 0; j < cols.length; j++){
                    //console.log(cols[j])
        row.push(cols[j].value);
    }
        
    csv.push(row.join(","));

 }
  // Download CSV file not posted here
  console.log(csv.join("\n")); 
}

Link to fiddle: https://jsfiddle.net/tewo2drn/1/

Upvotes: 2

Aaron
Aaron

Reputation: 1737

If you can ensure only inputs occur as child nodes inside a td you could use the following approach. When iterating over a td check if there are any child nodes (only happens in your example if an input is inside a td).

If there's a child (input) use .value on the child to get the value. Otherwise use .innerText. If there is something unclear, feel free to comment :)

function fetchData(filename) {
  var csv = [];
  var rows = document.getElementById('sample_table').querySelectorAll("table tr");

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

    var row = [],
      cols = rows[i].querySelectorAll("td, th");

    for (var j = 0; j < cols.length; j++) {
      if (cols[j].children.length > 0) { //assuming your structure is always the same and the table only contains inputs as child elements inside a td
        row.push(cols[j].firstChild.value);
      } else {
        row.push(cols[j].innerText);
      }
    }

    csv.push(row.join(","));

  }
  console.log(csv);
}
<table id="sample_table">
  <tr>
    <td>1</td>
    <td><input type="text" size="5" id="in2" name="txt2" value="0" /></td>
    <td><input type="text" size="5" id="in3" name="txt3" value="0" /></td>
    <td><input type="text" size="5" id="in4" name="txt4" value="0" /></td>
  </tr>
</table>
<button type="button" onclick="fetchData('myFile')">Export</button>

Upvotes: 3

keidakida
keidakida

Reputation: 751

What I think is you want to push each row's input value into a CSB file. Then you have to change you cols code like this

cols = document.querySelectorAll("td input, the input");
for (var j = 0; j < cols.length; j++){
    row.push(cols[j].value);
}

I think this would work

Upvotes: 2

Related Questions