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: