0

I would like to add a row to a table with 4 cells: indexnumber, firstname, lastname and points. As a newbie in Javascript I am complety lost in textnodes, childs and other Dom elements. Who can help creating a dynamic indexnumber like 1,2,3 in the first column etc..

var button = document.getElementById("addRow");
button.onclick = addRowFunc;
    
var firstName = document.getElementById("firstN"); 
var lastName = document.getElementById("lastN");
var points = document.getElementById("pnt");
       
function addRowFunc() {
    var tabel = document.getElementById("myTable");
    var row = tabel.insertRow(-1);
    var cel1 = row.insertCell(0);
    var cel2 = row.insertCell(1);
    var cel3 = row.insertCell(2);
    var cel4 = row.insertCell(3);
    cel1.value = function () {
        for (var i = 1; i < rij.length; i++) {
            //createTextNode .. 
        }
    }
    
    cel2.innerHTML = firstName.value;
    cel3.innerHTML = lastName.value;
    cel4.innerHTML = points.value;
}
<table id="myTable">
    <tr>
        <th>Rownumber</th>
        <th>FirstName</th>
        <th>LastName</th>
        <th>Points</th>
    </tr>

</table>
<br />
<br />
<br />
     FirstName <input type="text" id="firstN" /><br />
    LastName <input type="text" id="lastN" /><br />
    Points <input type="text" id="pnt" /> <br />
<br />
<button type="button" id="addRow">Add</button>
Tân
  • 1
  • 15
  • 56
  • 102
Tichel
  • 481
  • 2
  • 10
  • 24
  • Where do you define `rij`? Also, you can simply set the [`textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent) of a `` element, rather than creating multiple `textNode`s; `HTMLTableCell.textContent = "the element's text-content";` – David Thomas Mar 02 '17 at 13:07
  • I translated al to English, forgot this. rij must be row – Tichel Mar 02 '17 at 13:40
  • Ah, I used Google Translate and the best guess it offered was 'drive' (I *knew* I should have gone with my first instinct) :) Incidentally, is this what you're looking for: https://jsfiddle.net/davidThomas/t1qeLnn8/1/? – David Thomas Mar 02 '17 at 13:59
  • I think it is! Thank you – Tichel Mar 02 '17 at 14:08
  • You're very welcome indeed; answer added! :) – David Thomas Mar 02 '17 at 15:18
  • To be honest. I really appreciate your help and from the others. For me as a student JS I learn not a lot with receiving a complete new answer with small elements from my original script. – Tichel Mar 07 '17 at 09:41

3 Answers3

2

One approach to the problem you're facing, that of showing the number of the table-row element can be solved using CSS, with the following rules:

tbody {
  counter-reset: rownumber;
}
tr {
  counter-increment: rownumber;
}
td:first-child::before {
  content: counter(rownumber, decimal);
}

The above defines the counter, rownumber and has it be reset via the <tbody> element; so if rows are appended over multiple <tbody> elements then the <tr> descendants of each will be numbered independently of each other. If you'd prefer a continuous count of all <tr> elements then simply move the counter-reset rule up to the <table> element, or to any other (ideally the closest possible) ancestor within which you require a cumulative count.

This counter is incremented, by 1, in each <tr> element, and then shown in the ::before pseudo-element of the first <td> child of each <tr>. The second argument to counter() is the type of counter you wish to use (see this answer for the (current) possible options: https://stackoverflow.com/a/16943843/82548 (disclaimer: it's one of my answers, the second Snippet will allow you to see the results of different counter types).

So, that part covered I've also rewritten – I'd like to say revised or refactored, but that would be, at best, an understatement – your posted code into the following function. Code explained in the comments:

// a named function to call:
function addRow() {

  // using 'let' to declare variables, this is mostly a
  // matter of personal preference in this case, and if
  // 'let' is unavailable to you, or your users, can be
  // replaced with 'var'.

  // here we define a 'details' Object to hold the
  // variables from the <input> elements we find
  // later:
  let details = {},

  // we use document.querySelector() to retrieve the first,
  // if any, elements matching the supplied CSS selector;
  // this is the element to which new content will be added:
    target = document.querySelector('#myTable tbody'),

  // and again we use document.querySelector() to find the
  // element we'll be cloning in order to append the new
  // new content:
    source = document.querySelector('#myTable tfoot tr.template')
      // we pass (Boolean) true as an argument in order to copy
      // the descendants of the cloned node as well as the node
      // itself:
      .cloneNode(true),

    // here we use Array.from() to convert the Array-like
    // HTMLCollection returned from document.querySelectorAll()
    // (which retrieves all the elements which match the
    // supplied CSS selector) into an Array:
    inputs = Array.from(
      document.querySelectorAll('form label input')
    );

  // we make use of the Array, via Array methods such as,
  // here, Array.prototype.forEach(), which iterates over
  // the elements of the Array:
  inputs.forEach(

    // using an Arrow function, rather than the traditional
    // anonymous function; here 'input' refers to the current
    // Array element of the Array of <input> elements over
    // which we're iterating.

    // here we update the details Object, by adding a new
    // key (details[input.id]) and setting the value of that
    // key to the value (input.value) held in the <input>:
    input => details[input.id] = input.value
  );

  // here we convert the Array-like NodeList of child-
  // elements of the source (the <tr> element we cloned
  // earlier) into an Array, again using Array.from, and
  // then iterating over those elements using, again,
  // Array.prototype.forEach():
  Array.from(source.children).forEach(

    // in this Arrow function we're naming the
    // current Array-element 'cell', the name is
    // purely a personal choice, and can be almost
    // anything, so long as it's valid in JavaScript.

    // here we set the text-content of the current
    // cell (<td> element) to be equivalent to the
    // value held in the details Object at the same
    // custom data-* attribute, here data-from, as
    // the current <td> (details.cell.dataset.from);
    // if there is no key of that name, we set the
    // text to an empty String (''):
    cell => cell.textContent = details[cell.dataset.from] || ''
  );

  // we append the newly modified <tr> element to
  // the target element (the <tbody>):
  target.appendChild(source);

  // and here we iterate over the <input> elements:
  inputs.forEach(

    // and set the value of each <input> back to
    // its default value, the value it held on
    // page-load in order to save the user having
    // to first delete existing content before
    // entering new content to add:
    input => input.value = input.defaultValue
  );
}

document.querySelector('#addRow').addEventListener('click', addRow);

function addRow() {
  let details = {},
    target = document.querySelector('#myTable tbody'),
    source = document.querySelector('#myTable tfoot tr.template')
    .cloneNode(true),
    inputs = Array.from(
      document.querySelectorAll('form label input')
    );

  inputs.forEach(
    input => details[input.id] = input.value
  );

  Array.from(source.children).forEach(
    cell => cell.textContent = details[cell.dataset.from] || ''
  );

  target.appendChild(source);
  inputs.forEach(
    input => input.value = input.defaultValue
  );
}

document.querySelector('#addRow').addEventListener('click', addRow);
body {
  box-sizing: border-box;
}

label {
  display: block;
  width: 55%;
  overflow: hidden;
  margin: 0 0 0.5em 0;
}

table {
  table-layout: fixed;
  width: 90%;
  margin: 1em auto;
  border-collapse: collapse;
}

label input {
  width: 50%;
  float: right;
}

th,
td {
  border-left: 1px solid #000;
  border-bottom: 1px solid #000;
  line-height: 2em;
  height: 2em;
}

th {
  text-align: center;
}

th::after {
  content: ': ';
}

td:first-child,
th:first-child {
  border-left-color: transparent;
}

tbody {
  counter-reset: rownumber;
}

tbody tr {
  counter-increment: rownumber;
}

tbody td:first-child::before {
  content: counter(rownumber, decimal);
}

tfoot tr.template {
  display: none;
}
<form action="#">
  <fieldset>
    <legend>Add new details:</legend>
    <label>FirstName
      <input type="text" id="firstN" />
    </label>
    <label>LastName
      <input type="text" id="lastN" />
    </label>
    <label>Points
      <input type="text" id="pnt" />
    </label>
    <button type="button" id="addRow">Add</button>
  </fieldset>
</form>
<table id="myTable">
  <thead>
    <tr>
      <th>Rownumber</th>
      <th>FirstName</th>
      <th>LastName</th>
      <th>Points</th>
    </tr>
  </thead>
  <tfoot>
    <tr class="template">
      <td></td>
      <td data-from="firstN"></td>
      <td data-from="lastN"></td>
      <td data-from="pnt"></td>
    </tr>
  </tfoot>
  <tbody>
  </tbody>
</table>

JS Fiddle demo.

References:

Community
  • 1
  • 1
David Thomas
  • 249,100
  • 51
  • 377
  • 410
1

Here's the easiest way to get how nodes and DOM work :)

    var table = document.getElementById('myTable');
    var row = document.createElement('tr');
    var cell1 = document.createElement('td');
    var cell2 = document.createElement('td');
    var cell3 = document.createElement('td');
    var cell4 = document.createElement('td');

    cell1.innerHTML = '1';
    cell2.innerHTML = '2';
    cell3.innerHTML = '3';
    cell4.innerHTML = '4';

    row.appendChild(cell1);
    row.appendChild(cell2);
    row.appendChild(cell3);
    row.appendChild(cell4);

    table.appendChild(row);

so let's assume you have an Array of data formatted like:

data = [
    {
        indexNumber: 1,
        firstName: 'Bon',
        lastName: 'Jovi',
        points: 50,
    },
    {
        indexNumber: 2,
        firstName: 'Ann',
        lastName: 'Hathaway',
        points: 60,
    },
];

now you can process this Array in a forEach cycle:

var table = document.getElementById('myTable');

data.forEach(function(element) {
    var row = document.createElement('tr');
    var cell1 = document.createElement('td');
    var cell2 = document.createElement('td');
    var cell3 = document.createElement('td');
    var cell4 = document.createElement('td');

    cell1.innerHTML = element.indexNumber;
    cell2.innerHTML = element.firstName;
    cell3.innerHTML = element.lastName;
    cell4.innerHTML = element.points;

    row.appendChild(cell1);
    row.appendChild(cell2);
    row.appendChild(cell3);
    row.appendChild(cell4);

    table.appendChild(row);
});
andr1o
  • 249
  • 3
  • 7
  • thank you for your answer :) is this a static table, I am looking for a dynamic table. With a input table to feed. – Tichel Mar 02 '17 at 13:45
0

to insert a new row use append

<table id="mytable">
<tr><td >1</td> <td >sd</td> <td >sd</td> <td >sd</td></tr>
<tr><td >2</td> <td >sd</td> <td >sd</td> <td >sd</td></tr>
<tr><td >3</td> <td >sd</td> <td >sd</td> <td >sd</td></tr>
</table>

add this with jquery

  var total_rows = $('#mytable tr').length;
     var new_row = parseInt(total_rows)+parseInt(1);
    var yourdata_variable = "<tr><td >"+new_row+"</td> <td >sd2</td> <td >sd2</td> <td >sd2</td></tr>";
    $('#mytable').append(yourdata_variable);

if you just want to use javascript

var yourdata_variable = same as above;
var table = document.getElementById('mytable').append(yourdata_variable);

comment if this is what you want.

prabhjot
  • 394
  • 2
  • 6
  • 16