Add/Delete table rows dynamically using JavaScript - javascript

I'm trying to add/delete table rows following this example and this example.
Here's my code:
HTML Form
<div id="POItablediv">
<input type="button" id="addPOIbutton" value="Add POIs"/><br/><br/>
<table id="POITable" border="1">
<tr>
<td>POI</td>
<td>Latitude</td>
<td>Longitude</td>
<td>Delete?</td>
<td>Add Rows?</td>
</tr>
<tr>
<td>1</td>
<td><input size=25 type="text" id="latbox" readonly=true/></td>
<td><input size=25 type="text" id="lngbox" readonly=true/></td>
<td><input type="button" id="delPOIbutton" value="Delete" onclick="deleteRow(this)"/></td>
<td><input type="button" id="addmorePOIbutton" value="Add More POIs" onclick="insRow()"/></td>
</tr>
</table>
</div>
JavaScript
function deleteRow(row)
{
var i=row.parentNode.parentNode.rowIndex;
document.getElementById('POITable').deleteRow(i);
}
function insRow()
{
var x=document.getElementById('POITable').insertRow(1);
var c1=x.insertCell(0);
var c2=x.insertCell(1);
c1.innerHTML="NEW CELL1";
c2.innerHTML="NEW CELL2";
}
Now, as you can see, In my table I have text fields and buttons. What I want:
Just to repeat the structure of the row. I can't do it right now since innerHTM just takes texts. How can I insert a textfield or label?
The ids of the textfields should also be different since I'll retrieve the values later to put it in a database.
I want to put a function to increment the number of POIs as well
Can anyone help me out please?

You could just clone the first row that has the inputs, then get the nested inputs and update their ID to add the row number (and do the same with the first cell).
function deleteRow(row)
{
var i=row.parentNode.parentNode.rowIndex;
document.getElementById('POITable').deleteRow(i);
}
function insRow()
{
var x=document.getElementById('POITable');
// deep clone the targeted row
var new_row = x.rows[1].cloneNode(true);
// get the total number of rows
var len = x.rows.length;
// set the innerHTML of the first row
new_row.cells[0].innerHTML = len;
// grab the input from the first cell and update its ID and value
var inp1 = new_row.cells[1].getElementsByTagName('input')[0];
inp1.id += len;
inp1.value = '';
// grab the input from the first cell and update its ID and value
var inp2 = new_row.cells[2].getElementsByTagName('input')[0];
inp2.id += len;
inp2.value = '';
// append the new row to the table
x.appendChild( new_row );
}
Demo below
function deleteRow(row) {
var i = row.parentNode.parentNode.rowIndex;
document.getElementById('POITable').deleteRow(i);
}
function insRow() {
console.log('hi');
var x = document.getElementById('POITable');
var new_row = x.rows[1].cloneNode(true);
var len = x.rows.length;
new_row.cells[0].innerHTML = len;
var inp1 = new_row.cells[1].getElementsByTagName('input')[0];
inp1.id += len;
inp1.value = '';
var inp2 = new_row.cells[2].getElementsByTagName('input')[0];
inp2.id += len;
inp2.value = '';
x.appendChild(new_row);
}
<div id="POItablediv">
<input type="button" id="addPOIbutton" value="Add POIs" /><br/><br/>
<table id="POITable" border="1">
<tr>
<td>POI</td>
<td>Latitude</td>
<td>Longitude</td>
<td>Delete?</td>
<td>Add Rows?</td>
</tr>
<tr>
<td>1</td>
<td><input size=25 type="text" id="latbox" /></td>
<td><input size=25 type="text" id="lngbox" readonly=true/></td>
<td><input type="button" id="delPOIbutton" value="Delete" onclick="deleteRow(this)" /></td>
<td><input type="button" id="addmorePOIbutton" value="Add More POIs" onclick="insRow()" /></td>
</tr>
</table>

Easy Javascript Add more Rows with delete functionality
Cheers !
<TABLE id="dataTable">
<tr><td>
<INPUT TYPE=submit name=submit id=button class=btn_medium VALUE=\'Save\' >
<INPUT type="button" value="AddMore" onclick="addRow(\'dataTable\')" class="btn_medium" />
</td></tr>
<TR>
<TD>
<input type="text" size="20" name="values[]"/> <br><small><font color="gray">Enter Title</font></small>
</TD>
</TR>
</table>
<script>
function addRow(tableID) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var cell3 = row.insertCell(0);
cell3.innerHTML = cell3.innerHTML +' <input type="text" size="20" name="values[]"/> <INPUT type="button" class="btn_medium" value="Remove" onclick="this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);" /><br><small><font color="gray">Enter Title</font></small>';
//cell3.innerHTML = cell3.innerHTML +' <input type="text" size="20" name="values[]"/> <INPUT type="button" class="btn_medium" value="Remove" onclick="this.parentNode.parentNode.innerHTML=\'\';" /><br><small><font color="gray">Enter Title</font></small>';
}
</script>

This seems a lot cleaner than the answer above...
<script>
var maxID = 0;
function getTemplateRow() {
var x = document.getElementById("templateRow").cloneNode(true);
x.id = "";
x.style.display = "";
x.innerHTML = x.innerHTML.replace(/{id}/, ++maxID);
return x;
}
function addRow() {
var t = document.getElementById("theTable");
var rows = t.getElementsByTagName("tr");
var r = rows[rows.length - 1];
r.parentNode.insertBefore(getTemplateRow(), r);
}
</script>
<table id="theTable">
<tr>
<td>id</td>
<td>name</td>
</tr>
<tr id="templateRow" style="display:none">
<td>{id}</td>
<td><input /></td>
</tr>
</table>
<button onclick="addRow();">Go</button>

If you put a delete button on each row, then:
<tr>
<td><input type="button" value="Delete row" onclick="deleteRow(this);">
<td><input type="text">
<td><input type="text">
And the deleteRow function can be:
function deleteRow(el) {
// while there are parents, keep going until reach TR
while (el.parentNode && el.tagName.toLowerCase() != 'tr') {
el = el.parentNode;
}
// If el has a parentNode it must be a TR, so delete it
// Don't delte if only 3 rows left in table
if (el.parentNode && el.parentNode.rows.length > 3) {
el.parentNode.removeChild(el);
}
}
If all your rows have the same content, it will be much faster to add a row by cloning an existing row:
function addRow(tableID) {
var table = document.getElementById(tableID);
if (!table) return;
var newRow = table.rows[1].cloneNode(true);
// Now get the inputs and modify their names
var inputs = newRow.getElementsByTagName('input');
for (var i=0, iLen=inputs.length; i<iLen; i++) {
// Update inputs[i]
}
// Add the new row to the tBody (required for IE)
var tBody = table.tBodies[0];
tBody.insertBefore(newRow, tBody.lastChild);
}

You can add a row to a table in the most easiest way like this :-
I found this as an easiest way to add row . The awesome thing about this is that it doesn't change the already present table contents even if it contains input elements .
row = `<tr><td><input type="text"></td></tr>`
$("#table_body tr:last").after(row) ;
Here #table_body is the id of the table body tag .

1 & 2: innerHTML can take HTML as well as text. You could do something like:
c1.innerHTML = "<input size=25 type=\"text\" id='newID' readonly=true/>";
May or may not be the best way to do it, but you could do it that way.
3: I would just use a global variable that holds the number of POIs and increment/decrement it each time.

Here Is full code with HTML,CSS and JS.
<style><style id='generate-style-inline-css' type='text/css'>
body {
background-color: #efefef;
color: #3a3a3a;
}
a,
a:visited {
color: #1e73be;
}
a:hover,
a:focus,
a:active {
color: #000000;
}
body .grid-container {
max-width: 1200px;
}
body,
button,
input,
select,
textarea {
font-family: "Open Sans", sans-serif;
}
.entry-content>[class*="wp-block-"]:not(:last-child) {
margin-bottom: 1.5em;
}
.main-navigation .main-nav ul ul li a {
font-size: 14px;
}
#media (max-width:768px) {
.main-title {
font-size: 30px;
}
h1 {
font-size: 30px;
}
h2 {
font-size: 25px;
}
}
.top-bar {
background-color: #636363;
color: #ffffff;
}
.top-bar a,
.top-bar a:visited {
color: #ffffff;
}
.top-bar a:hover {
color: #303030;
}
.site-header {
background-color: #ffffff;
color: #3a3a3a;
}
.site-header a,
.site-header a:visited {
color: #3a3a3a;
}
.main-title a,
.main-title a:hover,
.main-title a:visited {
color: #222222;
}
.site-description {
color: #757575;
}
.main-navigation,
.main-navigation ul ul {
background-color: #222222;
}
.main-navigation .main-nav ul li a,
.menu-toggle {
color: #ffffff;
}
.main-navigation .main-nav ul li:hover>a,
.main-navigation .main-nav ul li:focus>a,
.main-navigation .main-nav ul li.sfHover>a {
color: #ffffff;
background-color: #3f3f3f;
}
button.menu-toggle:hover,
button.menu-toggle:focus,
.main-navigation .mobile-bar-items a,
.main-navigation .mobile-bar-items a:hover,
.main-navigation .mobile-bar-items a:focus {
color: #ffffff;
}
.main-navigation .main-nav ul li[class*="current-menu-"]>a {
color: #ffffff;
background-color: #3f3f3f;
}
.main-navigation .main-nav ul li[class*="current-menu-"]>a:hover,
.main-navigation .main-nav ul li[class*="current-menu-"] .sfHover>a {
color: #ffffff;
background-color: #3f3f3f;
}
.navigation-search input[type="search"],
.navigation-search input[type="search"]:active {
color: #3f3f3f;
background-color: #3f3f3f;
}
.navigation-search input[type="search"]:focus {
color: #ffffff;
background-color: #3f3f3f;
}
.main-navigation ul ul {
background-color: #3f3f3f;
}
.main-navigation .main-nav ul ul li a {
color: #ffffff;
}
.main-navigation .main-nav ul ul li:hover>a,
.main-navigation .main-nav ul ul li:focus>a,
.main-navigation .main-nav ul ul li.sfHover>a {
color: #ffffff;
background-color: #4f4f4f;
}
.main-navigation . main-nav ul ul li[class*="current-menu-"]>a {
color: #ffffff;
background-color: #4f4f4f;
}
.main-navigation .main-nav ul ul li[class*="current-menu-"]>a:hover,
.main-navigation .main-nav ul ul li[class*="current-menu-"] .sfHover>a {
color: #ffffff;
background-color: #4f4f4f;
}
.separate-containers .inside-article,
.separate-containers .comments-area,
.separate-containers .page-header,
.one-container .container,
.separate-containers .paging-navigation,
.inside-page-header {
background-color: #ffffff;
}
.entry-meta {
color: #595959;
}
.entry-meta a,
.entry-meta a:visited {
color: #595959;
}
.entry-meta a:hover {
color: #1e73be;
}
.sidebar .widget {
background-color: #ffffff;
}
.sidebar .widget .widget-title {
color: #000000;
}
.footer-widgets {
background-color: #ffffff;
}
.footer-widgets .widget-title {
color: #000000;
}
.site-info {
color: #ffffff;
background-color: #222222;
}
.site-info a,
.site-info a:visited {
color: #ffffff;
}
.site-info a:hover {
color: #606060;
}
.footer-bar .widget_nav_menu .current-menu-item a {
color: #606060;
}
input[type="text"],
input[type="email"],
input[type="url"],
input[type="password"],
input[type="search"],
input[type="tel"],
input[type="number"],
textarea,
select {
color: #666666;
background-color: #fafafa;
border-color: #cccccc;
}
input[type="text"]:focus,
input[type="email"]:focus,
input[type="url"]:focus,
input[type="password"]:focus,
input[type="search"]:focus,
input[type="tel"]:focus,
input[type="number"]:focus,
textarea:focus,
select:focus {
color: #666666;
background-color: #ffffff;
border-color: #bfbfbf;
}
button,
html input[type="button"],
input[type="reset"],
input[type="submit"],
a.button,
a.button:visited,
a.wp-block-button__link:not(.has-background) {
color: #ffffff;
background-color: #666666;
}
button:hover,
html input[type="button"]:hover,
input[type="reset"]:hover,
input[type="submit"]:hover,
a.button:hover,
button:focus,
html input[type="button"]:focus,
input[type="reset"]:focus,
input[type="submit"]:focus,
a.button:focus,
a.wp-block-button__link:not(.has-background):active,
a.wp-block-button__link:not(.has-background):focus,
a.wp-block-button__link:not(.has-background):hover {
color: #ffffff;
background-color: #3f3f3f;
}
.generate-back-to-top,
.generate-back-to-top:visited {
background-color: rgba( 0, 0, 0, 0.4);
color: #ffffff;
}
.generate-back-to-top:hover,
.generate-back-to-top:focus {
background-color: rgba( 0, 0, 0, 0.6);
color: #ffffff;
}
.entry-content .alignwide,
body:not(.no-sidebar) .entry-content .alignfull {
margin-left: -40px;
width: calc(100% + 80px);
max-width: calc(100% + 80px);
}
#media (max-width:768px) {
.separate-containers .inside-article,
.separate-containers .comments-area,
.separate-containers .page-header,
.separate-containers .paging-navigation,
.one-container .site-content,
.inside-page-header {
padding: 30px;
}
.entry-content .alignwide,
body:not(.no-sidebar) .entry-content .alignfull {
margin-left: -30px;
width: calc(100% + 60px);
max-width: calc(100% + 60px);
}
}
.rtl .menu-item-has-children .dropdown-menu-toggle {
padding-left: 20px;
}
.rtl .main-navigation .main-nav ul li.menu-item-has-children>a {
padding-right: 20px;
}
.one-container .sidebar .widget {
padding: 0px;
}
.append_row {
color: black !important;
background-color: #FFD6D6 !important;
border: 1px #ccc solid !important;
}
.append_column {
color: black !important;
background-color: #D6FFD6 !important;
border: 1px #ccc solid !important;
}
table#my-table td {
width: 50px;
height: 27px;
border: 1px solid #D3D3D3;
text-align: center;
padding: 0;
}
div#my-container input {
padding: 5px;
font-size: 12px !important;
width: 100px;
margin: 2px;
}
.row {
background-color: #FFD6D6 !important;
}
.col {
background-color: #D6FFD6 !important;
}
</style>
<script src="https://code.jquery.com/jquery-1.11.0.js"></script>
<script>
// append row to the HTML table
function appendRow() {
var tbl = document.getElementById('my-table'), // table reference
row = tbl.insertRow(tbl.rows.length), // append table row
i;
// insert table cells to the new row
for (i = 0; i < tbl.rows[0].cells.length; i++) {
createCell(row.insertCell(i), i, 'row');
}
}
// create DIV element and append to the table cell
function createCell(cell, text, style) {
var div = document.createElement('div'), // create DIV element
txt = document.createTextNode(text); // create text node
div.appendChild(txt); // append text node to the DIV
div.setAttribute('class', style); // set DIV class attribute
div.setAttribute('className', style); // set DIV class attribute for IE (?!)
cell.appendChild(div); // append DIV to the table cell
}
// append column to the HTML table
function appendColumn() {
var tbl = document.getElementById('my-table'), // table reference
i;
// open loop for each row and append cell
for (i = 0; i < tbl.rows.length; i++) {
createCell(tbl.rows[i].insertCell(tbl.rows[i].cells.length), i, 'col');
}
}
// delete table rows with index greater then 0
function deleteRows() {
var tbl = document.getElementById('my-table'), // table reference
lastRow = tbl.rows.length - 1, // set the last row index
i;
// delete rows with index greater then 0
for (i = lastRow; i > 0; i--) {
tbl.deleteRow(i);
}
}
// delete table columns with index greater then 0
function deleteColumns() {
var tbl = document.getElementById('my-table'), // table reference
lastCol = tbl.rows[0].cells.length - 1, // set the last column index
i, j;
// delete cells with index greater then 0 (for each row)
for (i = 0; i < tbl.rows.length; i++) {
for (j = lastCol; j > 0; j--) {
tbl.rows[i].deleteCell(j);
}
}
}
</script>
<div id="my-container">
<center><br>
<input type="button" value="Add row" onclick="javascript:appendRow()" class="append_row"><br>
<input type="button" value="Add column" onclick="javascript:appendColumn()" class="append_column"><br>
<input type="button" value="Delete rows" onclick="javascript:deleteRows()" class="delete"><br>
<input type="button" value="Delete columns" onclick="javascript:deleteColumns()" class="delete"><br>
<input type="button" value="Delete both" onclick="javascript:deleteColumns();deleteRows()" class="delete"><p></p>
<table id="my-table" align="center" cellspacing="0" cellpadding="0" border="0">
<tbody><tr>
<td>Small</td>
</tr>
</tbody></table>
<p></p></center>
</div>

Add or Delete row(s) dynamically!
<HTML>
<HEAD>
<TITLE> Add/Remove dynamic rows in HTML table </TITLE>
<style type="text/css">
.democlass{
color:red;
}
</style>
<SCRIPT language="javascript">
function addRow(tableID) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var colCount = table.rows[0].cells.length;
var row = table.insertRow(rowCount);
for(var i = 0; i < colCount; i++) {
var newcell = row.insertCell(i);
newcell.innerHTML = table.rows[0].cells[i].innerHTML;
}
row = table.insertRow(table.rows.length);
for(var i = 0; i < colCount; i++) {
var newcell = row.insertCell(i);
newcell.innerHTML = table.rows[1].cells[i].innerHTML;
}
row = table.insertRow(table.rows.length);
for(var i = 0; i < colCount; i++) {
var newcell = row.insertCell(i);
newcell.innerHTML = table.rows[2].cells[i].innerHTML;
}
row = table.insertRow(table.rows.length);
for(var i = 0; i < colCount; i++) {
var newcell = row.insertCell(i);
if(i == (colCount - 1)) {
newcell.innerHTML = "<INPUT type=\"button\" value=\"Delete Row\" onclick=\"removeRow(this)\"/>";
} else {
newcell.innerHTML = table.rows[3].cells[i].innerHTML;
}
}
}
/**
* This method deletes the specified section of the table
* OR deletes the specified rows from the table.
*/
function removeRow(src) {
var oRow = src.parentElement.parentElement;
var rowsCount = 0;
for(var index = oRow.rowIndex; index >= 0; index--) {
document.getElementById("dataTable").deleteRow(index);
if(rowsCount == (4 - 1)) {
return;
}
rowsCount++;
}
//once the row reference is obtained, delete it passing in its rowIndex
/* document.getElementById("dataTable").deleteRow(oRow.rowIndex); */
}
</SCRIPT>
</HEAD>
<BODY>
<form name="myForm">
<TABLE id="dataTable" width="350px" border="1">
<TR>
<TD>
<INPUT type="checkbox" name="chk"/>
</TD>
<TD>
Code
</TD>
<TD>
<INPUT type="text" name="txt"/>
</TD>
<TD>
Select Country
</TD>
<TD>
<SELECT name="country">
<OPTION value="in">India</OPTION>
<OPTION value="de">Germany</OPTION>
<OPTION value="fr">France</OPTION>
<OPTION value="us">United States</OPTION>
<OPTION value="ch">Switzerland</OPTION>
</SELECT>
</TD>
</TR>
<TR>
<TD> </TD>
<TD>
First Name
</TD>
<TD>
<INPUT type="text" name="txt1"/>
</TD>
<TD>
Last Name
</TD>
<TD>
<INPUT type="text" name="txt2"/>
</TD>
</TR>
<TR>
<TD> </TD>
<TD>Phone</TD>
<TD>
<INPUT type="text" name="txt3"/>
</TD>
<TD>Address</TD>
<TD>
<INPUT type="text" name="txt4" class="democlass"/>
</TD>
</TR>
<TR>
<TD> </TD>
<TD> </TD>
<TD>
</TD>
<TD> </TD>
<TD>
<INPUT type="button" value="Add Row" onclick="addRow('dataTable')" />
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

I used some of the solutions indicated above plus solutions from other postings to come up with a working solution for a dynamic table containing input fields. I'm doing this because it might help someone who finds this thread after searching for the same things that led me to it, and also because the accepted answer (and associated jsfiddle) doesn't actually work! That is, it doesn't index the table rows correctly after a number of inserts/deletes. The key issue is how to uniquely index the dynamic row data, which is possible with a bit of jquery:
<form id=frmLines>
<table id=tabLines>
<tr>
<td>img src='/some/suitable/graphic' onclick='removeLine(this);'/></td>
<td><input type='text' name='field1' /></td>
<td><input type='text' name='field2' /></td>
<td><input type='text' name='field3' /></td>
</tr>
<tr>
<td><img src='/some/suitable/graphic' onclick='addLine();' /></td>
<td colspan=3> </td>
</tr>
</table>
</form>
Note the form and table have id's for direct DOM referencing, but you can't use id's on the input fields as to make them unique you'd need to introduce an index which would massively complicate the code - and its easy enough to access them by name when the form is processed (see below)
Then the javascript to control adding and removing lines is like this:
function addLine() {
var tabLines = document.getElementById("tabLines");
var tabLinesRow = tabLines.insertRow(tabLines.rows.length-1);
var col1html = "<img src='/some/suitable/graphic' onclick='removeLine(this);'>";
var col2html = "<input type='text' name='field1' />";
var col3html = "<input type='text' name='field2' />";
var col4html = "<input type='text' name='field3' />";
var col1 = tabLinesRow.insertCell(0); col1.innerHTML=col1html;
var col2 = tabLinesRow.insertCell(1); col2.innerHTML=col2html;
var col3 = tabLinesRow.insertCell(2); col3.innerHTML=col3html;
var col4 = tabLinesRow.insertCell(3); col4.innerHTML=col4html;
}
function removeLine(lineItem) {
var row = lineItem.parentNode.parentNode;
row.parentNode.removeChild(row);
}
Then the final part of the jigsaw - the javascript to process the form data when its submitted. The key jquery function here is .eq() - which allows you to access the field names in the order they appear in the form - i.e. in table row order.
var frmData = {}; // an object to contain all form data
var arrLines = new Array(); // array to contain the dynamic lines
var tabLines = document.getElementById("tabLines").rows.length-1;
for (i=0;i<tabLines;i++) {
arrLines[i] = {};
arrLines[i]['no'] = i+1;
arrLines[i]['field1'] = $("#frmLines input[name=field1]").eq(i).val();
arrLines[i]['field2'] = $("#frmLines input[name=field2]").eq(i).val();
arrLines[i]['field3'] = $("#frmLines input[name=field3]").eq(i).val();
}
frmData['lines'] = arrLines;
frmData['another_field'] = $('#frmLines input[name=another_field]").val();
var jsonData = JSON.stringify(frmData);
// lines of data now in a JSON structure as indexed array
// (plus other fields in the JSON as required)
// ready to post via ajax etc
I hope this helps someone, either directly or indirectly. There are a couple of subtle techniques being used which aren't that complicated but took me 3-4 hours to piece together.

Javascript dynamically adding table data.
SCRIPT
function addRow(tableID) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var colCount = table.rows[0].cells.length;
var validate_Noof_columns = (colCount - 1); // •No Of Columns to be Validated on Text.
for(var j = 0; j < colCount; j++) {
var text = window.document.getElementById('input'+j).value;
if (j == validate_Noof_columns) {
row = table.insertRow(2); // •location of new row.
for(var i = 0; i < colCount; i++) {
var text = window.document.getElementById('input'+i).value;
var newcell = row.insertCell(i);
if(i == (colCount - 1)) { // Replace last column with delete button
newcell.innerHTML = "<INPUT type='button' value='X' onclick='removeRow(this)'/>"; break;
} else {
newcell.innerHTML = text;
window.document.getElementById('input'+i).value = '';
}
}
}else if (text != 'undefined' && text.trim() == ''){
alert('input'+j+' is EMPTY');break;
}
}
}
function removeRow(onclickTAG) {
// Iterate till we find TR tag.
while ( (onclickTAG = onclickTAG.parentElement) && onclickTAG.tagName != 'TR' );
onclickTAG.parentElement.removeChild(onclickTAG);
}
HTMl
<div align='center'>
<TABLE id='dataTable' border='1' >
<TBODY>
<TR><th align='center'><b>First Name:</b></th>
<th align='center' colspan='2'><b>Last Name:</b></th>
<th></th>
</TR>
<TR><TD ><INPUT id='input0' type="text"/></TD>
<TD ><INPUT id='input1' type='text'/></TD>
<TD>
<INPUT type='button' id='input2' value='+' onclick="addRow('dataTable')" />
</TD>
</TR>
</TBODY>
</TABLE>
</div>
Example : jsfiddle

Related

Error or bug when switching CSS classes by JavaScript when dragging with mouse [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
Ok, here a simple code, which changes td class when you click on them:
const btn = document.getElementsByTagName("input")[0];
btn.addEventListener("click", function(event){
let cells = document.getElementsByTagName("td");
for (let i=0; i<cells.length; i++) {
cells[i].classList = ""
};
CounterCells();
})
const tabl = document.getElementsByTagName("table")[0];
tabl.addEventListener("click", function(event){
if (event.target.classList == ""){
event.target.classList.add("green");
console.log("Nothing to green");
} else if (event.target.classList.contains("white")){
event.target.classList.replace("white", "green");
console.log("White to green");
} else if (event.target.classList.contains("green")){
event.target.classList.replace("green", "red");
console.log("Green to red");
} else if (event.target.classList.contains("red")) {
event.target.classList.replace("red", "white");
console.log("Red to white");
}
CounterCells();
})
function CounterCells() {
let cells = document.getElementsByTagName("td");
let countWhites = 0;
let countGreens = 0;
let countReds = 0;
for (let i=0; i<cells.length; i++) {
if (cells[i].classList == "") {
countWhites++
}
if (cells[i].classList.contains("white")) {
countWhites++
}
if (cells[i].classList.contains("green")) {
countGreens++
}
if (cells[i].classList.contains("red")) {
countReds++
}
}
const p = document.getElementById("demo");
p.innerHTML = "Whites: "+countWhites+"<br> Greens: "+countGreens+"<br> Reds: "+countReds;
}
table {
border-collapse: collapse;
}
td {
border: 1px solid grey;
width: 2rem;
height: 2rem;
text-align: center;
cursor: pointer;
user-select: none;
}
.green {
background-color: green;
}
.red {
background-color: red;
}
.white {
background-color: white;
}
<input type="button" value="Reset">
<br>
<br>
<table>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>4</td>
<td>5</td>
<td>6</td>
</tr>
<tr>
<td>7</td>
<td>8</td>
<td>9</td>
</tr>
</table>
<p id="demo"></p>
If you click it -- anything works fine, but now try to click on cell number one and drag mouse over cell number three and then release mouse button -- class will be assigned to tr not to last td number 3.
Why is that?
https://jsfiddle.net/foxnadir/Ls6p7j1z/3/
The problem in your code was that you were attaching the click event to the table element, when only one td can be clicked at a time.
I also changed the event from click to mousedown so that when the user drags from 1 to 3, 1 changes color, but if this behavior is not what you wanted, you can change it back.
Here is the working code:
const btn = document.getElementsByTagName("input")[0];
btn.addEventListener("click", function(event) {
let cells = document.getElementsByTagName("td");
for (let i = 0; i < cells.length; i++) {
cells[i].classList = ""
};
CounterCells();
})
let cells = document.getElementsByTagName("td");
for (i = 0; i < cells.length; i++) {
cells[i].addEventListener("mousedown", function(event) {
if (event.target.classList == "") {
event.target.classList.add("green");
console.log("Nothing to green");
} else if (event.target.classList.contains("white")) {
event.target.classList.replace("white", "green");
console.log("White to green");
} else if (event.target.classList.contains("green")) {
event.target.classList.replace("green", "red");
console.log("Green to red");
} else if (event.target.classList.contains("red")) {
event.target.classList.replace("red", "white");
console.log("Red to white");
}
CounterCells();
})
}
function CounterCells() {
let countWhites = 0;
let countGreens = 0;
let countReds = 0;
for (let i = 0; i < cells.length; i++) {
if (cells[i].classList == "") {
countWhites++
}
if (cells[i].classList.contains("white")) {
countWhites++
}
if (cells[i].classList.contains("green")) {
countGreens++
}
if (cells[i].classList.contains("red")) {
countReds++
}
}
const p = document.getElementById("demo");
p.innerHTML = "Whites: " + countWhites + "<br> Greens: " + countGreens + "<br> Reds: " + countReds;
}
table {
border-collapse: collapse;
}
td {
border: 1px solid grey;
width: 2rem;
height: 2rem;
text-align: center;
cursor: pointer;
user-select: none;
}
tr {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
td {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.green {
background-color: green;
}
.red {
background-color: red;
}
.white {
background-color: white;
}
<input type="button" value="Reset">
<br>
<br>
<table>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>4</td>
<td>5</td>
<td>6</td>
</tr>
<tr>
<td>7</td>
<td>8</td>
<td>9</td>
</tr>
</table>
<p id="demo"></p>

How to add a number dynamically with Javascript to the first cell

I'm learning Javascript and i'm stuck at the moment. When the user input their first name, last name, age and clicks on the button "add", 1 new row and 4 new cells are being added to the table with the value of the users input.
My question is: how do I get the first cell to be a number? Which in this case should be number 4. If the user adds another row with value it should become number 5. etc.
If somebody could point me in a direction or show me another way to do it, that would help. Thanks! (css added just for visuals)
function allID(id) {
return document.getElementById(id);
}
function allEvents() {
allID("voegdatatoe").onclick = function () {
voegToeGegevens();
};
}
allEvents();
function voegToeGegevens() {
var formulier = allID("invoerformulier");
var nieuweGegevens = [];
for (var i = 0; i < formulier.length; i++) {
nieuweGegevens[i] = formulier.elements[i].value;
}
var uitvoertabel = allID("uitvoertabel");
var nieuweRij = uitvoertabel.insertRow(-1);
for (i = 0; i < 4; i++) {
var NieuweCell = nieuweRij.insertCell(i);
NieuweCell.innerHTML = nieuweGegevens[i];
}
}
var row = document.getElementsByClassName("rownmr");
var i = 0;
for (i = 0; i < row.length; i++) {
row[i].innerHTML = i + 1;
}
table,
th,
td {
border-collapse: collapse;
border: 1px solid black;
}
th,
td {
padding: 5px;
}
th {
text-align: left;
background-color: #c95050;
color: white;
}
.uitvoertabel {
width: 60%;
}
.uitvoertabel tr:nth-child(even) {
background-color: #eee;
}
.uitvoertabel tbody tr td:first-child {
width: 30px;
}
.invoerform {
margin-top: 50px;
width: 30%;
}
.invoerform input,
label {
display: block;
}
.invoerform label {
margin-bottom: 5px;
margin-top: 10px;
}
#voegdatatoe {
margin-top: 30px;
}
input:focus {
border: 1px solid #d45757;
outline: none;
}
<table class="uitvoertabel" id="uitvoertabel">
<thead>
<tr>
<th></th>
<th>Voornaam</th>
<th>Achternaam</th>
<th>Leeftijd</th>
</tr>
</thead>
<tbody>
<tr>
<td class="rownmr"></td>
<td>Johan</td>
<td>cruijff</td>
<td>54</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Frans</td>
<td>Bauer</td>
<td>47</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Willem</td>
<td>van Oranje</td>
<td>80</td>
</tr>
</tbody>
</table>
<form action="" id="invoerformulier" class="invoerform">
<label>Voornaam:</label>
<input type="text" name="vnaam" id="voornaam">
<label>Achternaam:</label>
<input type="text" name="anaam" id="achternaam">
<label>Leeftijd:</label>
<input type="text" name="points" id="leeftijd">
</form>
<button id="voegdatatoe">Voeg toe</button>
There are a number of ways you could store this information, from a global variable (not recommended) to some local closure, or even localStorage. But you have the information in the DOM, so it might be simplest to use it.
One way to do this would be to scan the ids, find their maximum, and add one to it. This involves a few changes to your code. First, we would add some code to scan your id cells for the largest value:
var rows = document.getElementsByClassName("rownmr");
var highestId = Math.max(...([...rows].map(row => Number(row.textContent))))
Then we would start your content array with a new value one higher than that maximum:
var nieuweGegevens = [highestId + 1];
And your loop needs to take this into account by adding one to the index
for (var i = 0; i < formulier.length; i++) {
nieuweGegevens[i + 1] = formulier.elements[i].value;
}
Finally, we need to add the right class to that new cell so that on the next call, it will continue to work:
for (i = 0; i < 4; i++) {
var NieuweCell = nieuweRij.insertCell(i);
NieuweCell.innerHTML = nieuweGegevens[i];
if (i === 0) { /**** new ****/
NieuweCell.classList.add("rownmr") /**** new ****/
} /**** new ****/
}
You can see these changes inline in this snippet:
function allID(id) {
return document.getElementById(id);
}
function allEvents() {
allID("voegdatatoe").onclick = function () {
voegToeGegevens();
};
}
allEvents();
function voegToeGegevens() {
var formulier = allID("invoerformulier");
var rows = document.getElementsByClassName("rownmr");
var highestId = Math.max(...([...rows].map(row => Number(row.textContent))))
var nieuweGegevens = [highestId + 1];
for (var i = 0; i < formulier.length; i++) {
nieuweGegevens[i + 1] = formulier.elements[i].value;
}
var uitvoertabel = allID("uitvoertabel");
var nieuweRij = uitvoertabel.insertRow(-1);
for (i = 0; i < 4; i++) {
var NieuweCell = nieuweRij.insertCell(i);
NieuweCell.innerHTML = nieuweGegevens[i];
if (i === 0) {
NieuweCell.classList.add("rownmr")
}
}
}
var row = document.getElementsByClassName("rownmr");
var i = 0;
for (i = 0; i < row.length; i++) {
row[i].innerHTML = i + 1;
}
table,
th,
td {
border-collapse: collapse;
border: 1px solid black;
}
th,
td {
padding: 5px;
}
th {
text-align: left;
background-color: #c95050;
color: white;
}
.uitvoertabel {
width: 60%;
}
.uitvoertabel tr:nth-child(even) {
background-color: #eee;
}
.uitvoertabel tbody tr td:first-child {
width: 30px;
}
.invoerform {
margin-top: 50px;
width: 30%;
}
.invoerform input,
label {
display: block;
}
.invoerform label {
margin-bottom: 5px;
margin-top: 10px;
}
#voegdatatoe {
margin-top: 30px;
}
input:focus {
border: 1px solid #d45757;
outline: none;
}
<table class="uitvoertabel" id="uitvoertabel">
<thead>
<tr>
<th></th>
<th>Voornaam</th>
<th>Achternaam</th>
<th>Leeftijd</th>
</tr>
</thead>
<tbody>
<tr>
<td class="rownmr"></td>
<td>Johan</td>
<td>cruijff</td>
<td>54</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Frans</td>
<td>Bauer</td>
<td>47</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Willem</td>
<td>van Oranje</td>
<td>80</td>
</tr>
</tbody>
</table>
<form action="" id="invoerformulier" class="invoerform">
<label>Voornaam:</label>
<input type="text" name="vnaam" id="voornaam">
<label>Achternaam:</label>
<input type="text" name="anaam" id="achternaam">
<label>Leeftijd:</label>
<input type="text" name="points" id="leeftijd">
</form>
<button id="voegdatatoe">Voeg toe</button>
Note that this will continue to work on subsequent adds.
Add additional the length+1 param in the arrays of data
function allID(id) {
return document.getElementById(id);
}
function allEvents() {
allID("voegdatatoe").onclick = function () {
voegToeGegevens();
};
}
allEvents();
function voegToeGegevens() {
var row = document.getElementsByTagName("tr");
var formulier = allID("invoerformulier");
var nieuweGegevens = [];
nieuweGegevens.push(row.length) //length param for first column
for (var i = 0; i < formulier.length; i++) {
nieuweGegevens[i+1] = formulier.elements[i].value; //saving values from i=1
}
var uitvoertabel = allID("uitvoertabel");
var nieuweRij = uitvoertabel.insertRow(-1);
for (i = 0; i < 4; i++) {
var NieuweCell = nieuweRij.insertCell(i);
NieuweCell.innerHTML = nieuweGegevens[i];
}
}
var row = document.getElementsByClassName("rownmr");
var i = 0;
for (i = 0; i < row.length; i++) {
row[i].innerHTML = i + 1;
}
table,
th,
td {
border-collapse: collapse;
border: 1px solid black;
}
th,
td {
padding: 5px;
}
th {
text-align: left;
background-color: #c95050;
color: white;
}
.uitvoertabel {
width: 60%;
}
.uitvoertabel tr:nth-child(even) {
background-color: #eee;
}
.uitvoertabel tbody tr td:first-child {
width: 30px;
}
.invoerform {
margin-top: 50px;
width: 30%;
}
.invoerform input,
label {
display: block;
}
.invoerform label {
margin-bottom: 5px;
margin-top: 10px;
}
#voegdatatoe {
margin-top: 30px;
}
input:focus {
border: 1px solid #d45757;
outline: none;
}
<table class="uitvoertabel" id="uitvoertabel">
<thead>
<tr>
<th></th>
<th>Voornaam</th>
<th>Achternaam</th>
<th>Leeftijd</th>
</tr>
</thead>
<tbody>
<tr>
<td class="rownmr"></td>
<td>Johan</td>
<td>cruijff</td>
<td>54</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Frans</td>
<td>Bauer</td>
<td>47</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Willem</td>
<td>van Oranje</td>
<td>80</td>
</tr>
</tbody>
</table>
<form action="" id="invoerformulier" class="invoerform">
<label>Voornaam:</label>
<input type="text" name="vnaam" id="voornaam">
<label>Achternaam:</label>
<input type="text" name="anaam" id="achternaam">
<label>Leeftijd:</label>
<input type="text" name="points" id="leeftijd">
</form>
<button id="voegdatatoe">Voeg toe</button>
As I note that none of the answers made, does not seem to have the approval of Niekket (no validation for anybody),
and that the question asked is accompanied by a very rough example (the author admits to being bloked in his apprenticeship), using a lot of useless code...
So I propose this complete solution, which I hope is enlightening enough on the proper way of coding its problem ( imho ).
const
TableBody_uitvoertabel = document.querySelector('#uitvoertabel > tbody'),
form_invoerformulier = document.querySelector('#invoerformulier'),
in_voornaam = document.querySelector('#voornaam'),
in_achternaam = document.querySelector('#achternaam'),
in_leeftijd = document.querySelector('#leeftijd')
;
var
RowCount = 0; // global..
// place numbers in the first column
document.querySelectorAll('#uitvoertabel > tbody > tr td:first-child').forEach(
elmTR=>{ elmTR.textContent = ++RowCount }
);
form_invoerformulier.onsubmit = function(e) {
e.preventDefault();
let
column = 0,
row = TableBody_uitvoertabel.insertRow(-1)
;
row.insertCell(column++).textContent = ++RowCount;
row.insertCell(column++).textContent = in_voornaam.value;
row.insertCell(column++).textContent = in_achternaam.value;
row.insertCell(column++).textContent = in_leeftijd.value;
this.reset();
}
table, th, td {
border-collapse: collapse;
border: 1px solid black;
}
th, td { padding: 5px; }
th {
text-align: left;
background-color: #c95050;
color: white;
}
table.uitvoertabel { width: 60%; }
table.uitvoertabel tr:nth-child(even) {
background-color: #eee;
}
table.uitvoertabel tbody tr td:first-child {
width: 30px;
}
form.invoerform {
margin-top: 50px;
width: 30%;
}
form.invoerform input,
form.invoerform label {
display: block;
}
form.invoerform label {
margin-bottom: 5px;
margin-top: 10px;
}
form.invoerform button {
margin-top: 30px;
}
form.invoerform input:focus {
border-color: #d45757;
outline: none;
}
<table class="uitvoertabel" id="uitvoertabel">
<thead>
<tr>
<th></th><th>Voornaam</th><th>Achternaam</th><th>Leeftijd</th>
</tr>
</thead>
<tbody>
<tr>
<td></td><td>Johan</td><td>cruijff</td><td>54</td>
</tr>
<tr>
<td></td><td>Frans</td><td>Bauer</td><td>47</td>
</tr>
<tr>
<td></td><td>Willem</td><td>van Oranje</td><td>80</td>
</tr>
</tbody>
</table>
<form id="invoerformulier" class="invoerform">
<label>Voornaam:</label>
<input type="text" name="vnaam" id="voornaam">
<label>Achternaam:</label>
<input type="text" name="anaam" id="achternaam">
<label>Leeftijd:</label>
<input type="text" name="points" id="leeftijd">
<button type="submit">Voeg toe</button>
<button type="reset">Reset</button>
</form>
I think that the main issue is that you only manually set the rownmrs for the first time from line var row = document.getElementsByClassName("rownmr");
rather than every time you click on the "Voeg toe" button.
Ideally, for your hard coded numbers, they would be in the markup and the logic to grab the next rownmr to display and the adding of that cell happens on click.
html
<table class="uitvoertabel" id="uitvoertabel">
<thead>
<tr>
<th></th>
<th>Voornaam</th>
<th>Achternaam</th>
<th>Leeftijd</th>
</tr>
</thead>
<tbody>
<tr>
<td class="rownmr">1</td>
<td>Johan</td>
<td>cruijff</td>
<td>54</td>
</tr>
<tr>
<td class="rownmr">2</td>
<td>Frans</td>
<td>Bauer</td>
<td>47</td>
</tr>
<tr>
<td class="rownmr">3</td>
<td>Willem</td>
<td>van Oranje</td>
<td>80</td>
</tr>
</tbody>
</table>
<form action="" id="invoerformulier" class="invoerform">
<label>Voornaam:</label>
<input type="text" name="vnaam" id="voornaam">
<label>Achternaam:</label>
<input type="text" name="anaam" id="achternaam">
<label>Leeftijd:</label>
<input type="text" name="points" id="leeftijd">
</form>
<button id="voegdatatoe">Voeg toe</button>
js
function allID(id) {
return document.getElementById(id);
}
function allEvents() {
allID("voegdatatoe").onclick = function () {
voegToeGegevens();
};
}
allEvents();
function voegToeGegevens() {
var formulier = allID("invoerformulier");
var nieuweGegevens = [];
for (var i = 0; i < formulier.length; i++) {
nieuweGegevens[i] = formulier.elements[i].value;
}
var allRownmrs = document.getElementsByClassName('rownmr');
var lastRownmr = allRownmrs[allRownmrs.length - 1].innerHTML;
var nextRownmr = parseInt(lastRownmr) + 1;
var uitvoertabel = allID("uitvoertabel");
var nieuweRij = uitvoertabel.insertRow(-1);
for (i = 0; i < 4; i++) {
var NieuweCell = nieuweRij.insertCell(i)
// you probably can refactor here
if (i === 0) {
NieuweCell.innerHTML = nextRownmr
} else {
NieuweCell.innerHTML = nieuweGegevens[i - 1];
}
}
}

Jquery filter table if fits into input range

Question:
I have a HTML with type number i want to ge the value using jQuery create a range by adding 10% on either side then checking if each row falls in the range if not hide the row.
Code:
HTML
<input type="number" id="myPrice" onkeyup="myPriceFunction()" placeholder="Enter amount.." title="Type in a amount" min="0">
JavaScript/jQuery
$(document).ready(function(){
$("#myPrice").on("keyup", function() {
priceLow = $(this).val() * 0.9;
priceHigh = $(this).val() * 1.1;
});
});
JS fiddle
https://jsfiddle.net/nx30zqjd/7/
Other:
I am using:
.addClass('discarded').hide();
.removeClass('discarded').show();
to hide and show rows
Expected Results:
I want the range to be created with priceLow and priceHigh then get price column get rid of $ and check if it falls within range if not hide using code above.
Update:
I added
$(this).closest('tr').removeClass('discarded').show();
} else {
$(this).closest('tr').addClass('discarded').hide();
}
however then this shows nothing because i don't check discarded rows, if i remove the check for discarded rows it doesn't apply my search to the range not sure if there is a easy way to have both but it seems to be ok for the moment
If you need any more information please ask.
Thanks
You can use this, you just need to iterate and get the values and then check, based on that you can hide and show.
$("#myPrice").on("keyup", function() {
if ($(this).val() === '') {
$("#myTable tr").show();
return;
}
priceLow = $(this).val() * 0.9;
priceHigh = $(this).val() * 1.1;
$("#myTable tr td:nth-child(2)").each(function(e) {
var value = this.textContent.replace('$', '');
if (value >= priceLow && value <= priceHigh) {
$(this).closest('tr').show();
} else {
$(this).closest('tr').hide();
}
})
});
$(document).ready(function() {
});
$(document).ready(function() {
$("#myPrice").on("keyup", function() {
if ($(this).val() === '') {
$("#myTable tr").show();
return;
}
priceLow = $(this).val() * 0.9;
priceHigh = $(this).val() * 1.1;
$("#myTable tr td:nth-child(2)").each(function(e) {
var value = parseFloat(this.textContent.replace('$', ''));
if (value >= priceLow && value <= priceHigh) {
$(this).closest('tr').removeClass('discarded').show();
} else {
$(this).closest('tr').addClass('discarded').hide();
}
})
});
});
<style>* {
box-sizing: border-box;
}
#mySearch {
background-image: url('https://www.w3schools.com/css/searchicon.png');
background-position: 10px 10px;
background-repeat: no-repeat;
width: 100%;
font-size: 16px;
padding: 12px 20px 12px 40px;
border: 1px solid #ddd;
margin-bottom: 12px;
}
#myTable {
border-collapse: collapse;
width: 100%;
border: 1px solid #ddd;
font-size: 18px;
}
#myTable th,
#myTable td {
text-align: left;
padding: 12px;
}
#myTable tr {
border-bottom: 1px solid #ddd;
}
.show {
display: block;
}
a {
color: blue;
text-decoration: none;
/* no underline */
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h2>CPUs</h2>
CPU
Motherboards
<input type="number" id="myPrice" placeholder="Enter amount.." title="Type in a amount" min="0">
<input type="text" id="mySearch" placeholder="Search for cpus.." title="Type in a cpu name">
<table id='myTable'>
<thead>
<tr>
<th>CPU</th>
<th>Price</th>
<th>Mark</th>
<th>Value</th>
<th>Socket</th>
<th>Image</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href='mobo.php?cpu_name=AMD Ryzen 5 2600"' target='_blank'>AMD Ryzen 5 2600</a></td>
<td>$246.05</td>
<td>13537</td>
<td>55.02</td>
<td>AM4</td>
<td><img src=NA height='42' width='42'></td>
</tr>
</tbody>
<tbody>
<tr>
<td><a href='mobo.php?cpu_name=Intel Core i7-8700K"' target='_blank'>Intel Core i7-8700K</a></td>
<td>$585.90</td>
<td>15957</td>
<td>27.24</td>
<td>LGA1151</td>
<td><img src=". $row[" url "]." height='42' width='42'></td>
</tr>
</tbody>
</table>

How to addEventListener to table cells

I'want to add an eventListener to the table cells so each time a table cell is clicked to execute a function .
var getDaysInMonth = function (year, month) {
return new Date(year, month, 0).getDate();
}
var calendar = {
month: function () {
var d = new Date();
return d.getMonth() + this.nextMonth;
},
year: function () {
var y = new Date();
return y.getFullYear();
},
nextMonth: 1,
cellColor: 'white',
}
var loopTable = function () {
var daysInMonth = getDaysInMonth(calendar.year(), calendar.month());
var table = document.getElementById('myTable');
var rows = table.rows;
var l = 1;
var month = calendar.month();
var year = calendar.year();
var firstDay = new Date(year + "-" + month).getDay();
var currentDay = new Date().getDay();
var dayOfMonth = new Date().getDate();
for (let i = 1; i < rows.length; i++) {
if (rows[i] == rows[1]) {
var k = 1;
for (let j = firstDay; j < rows[i].cells.length; j++) {
if (k === dayOfMonth && calendar.nextMonth === 1) {
rows[i].cells[j].style.backgroundColor = calendar.cellColor;
}
if (k <= daysInMonth) {
rows[i].cells[j].innerHTML = k;
k++
}
}
} else {
for (let j = 0; j < rows[i].cells.length; j++) {
if (k === dayOfMonth && calendar.nextMonth === 1) {
rows[i].cells[j].style.backgroundColor = calendar.cellColor;
}
if (k <= daysInMonth) {
rows[i].cells[j].innerHTML = k;
k++
}
}
}
}
}
loopTable();
clickCell();
function monthTitle() {
var monthsArray = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.', 'Sept.', 'Oct.', 'Nov.', 'Dec.'];
monthNum = calendar.month();
var monthName = monthsArray[calendar.month() - 1] + '' + calendar.year();
var title = document.getElementById('calendarTitle');
var nextArrow = document.getElementById('nxt');
var leftArrow = document.getElementById('prev');
if (monthName === ('Dec.' + '' + calendar.year())){
xmas();
}
if (monthNum >= 12) {
nextArrow.className += ' inactiveLink';
} else if (monthNum <= 1) {
leftArrow.className += ' inactiveLink';
} else {
nextArrow.classList.remove('inactiveLink');
leftArrow.classList.remove('inactiveLink');
}
title.innerHTML = '';
var titleNode = document.createTextNode(monthName);
title.appendChild(titleNode);
}
monthTitle();
function nextMonth() {
clearTable();
calendar.nextMonth += 1;
monthTitle();
loopTable();
}
function previousMonth() {
clearTable();
calendar.nextMonth -= 1;
monthTitle();
loopTable();
}
function clearTable() {
var table = document.getElementById('myTable');
var rows = table.rows;
for (var i = 1; i < rows.length; i++) {
cells = rows[i].cells;
for (var j = 0; j < cells.length; j++) {
if (cells[j].innerHTML = '') {
cells[j].style.display = 'none';
}
cells[j].innerHTML = '';
cells[j].style.backgroundColor = '#D9534F';
cells[j].style.emptyCells = 'hide';
}
}
}
var next = document.getElementById('nxt');
var previous = document.getElementById('prev');
var table = document.getElementById('myTable');
var cell = table.rows;
next.addEventListener('click', nextMonth);
previous.addEventListener('click', previousMonth);
function clickCell() {
var row = document.getElementById('myTable').rows;
for (var i = 0; i < row.length; i++) {
for (var j = 0; j < row[i].cells.length; j++ ) {
row[i].cells[j].addEventListener('click', function(){
console.log('click');
})
}
}
}
clickCell();
body {
background-color: rgb(0, 121, 191);
}
table {
width: 50%;
background-color: #D9534F;
border: 1px solid white;
padding: 10px;
padding-bottom: 20px;
font-size: 25px;
border-radius: 25px;
position: relative;
margin: auto;
}
td {
border: 1px solid white;
text-align: center;
font-weight: 600;
font-size: 20px;
padding: 20px;
}
th {
height: 50px;
}
.calArrows {
text-decoration: none;
color: white;
font-size: 35px;
}
#nxt {
font-size: 30px;
position: absolute;
top: 0;
right: 25%
}
#prev {
font-size: 30px;
position: absolute;
top: 0;
left: 25%;
}
#calendarTitle {
font-family: 'Indie Flower', cursive;
font-weight: 600;
font-size: 25px;
color: white;
}
.inactiveLink {
cursor: not-allowed;
pointer-events: none;
}
#myTable {
empty-cells: hide;
}
.xmasDec {
width: 90%;
height: 70%;
position: absolute;
top: -10%;
left: 5%;
}
#calWraper {
position: relative;
}
#myCan {
position: absolute;
top: 0;
left: 10%;
width: 90%;
height: 70%;
opacity: 0, 5;
}
<body>
<canvas class="myCan" width="100" height="100"></canvas>
<div id="calWraper">
<table id="myTable">
<caption id="calendarTitle">Test</caption>
<tr>
<th>Sun</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thur</th>
<th>Fri</th>
<th>Sat</th>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
<canvas id="myCan" width="200" height="200" style="background-color: transparent"></canvas>
<i class="fa fa-arrow-left" ></i>
<i class="fa fa-arrow-right" ></i>
</div>
</html>
I tried by creating a function that it will loop through rows and cells and add the eventListener to each . But it seems that its not working , its working on random instances which is really strange behavior . Here is the function i create:
function clickCell() {
var row = document.getElementById('myTable').rows;
for (var i = 0; i < row.length; i++) {
for (var j = 0; j < row[i].cells.length; j++ ) {
console.log(row[i].cells[j].innerHTML);
row[i].cells[j].addEventListener('click', function(){
console.log('click');
})
}
}
}
It seems your canvas is overlapping your table. Because of that td elements in your table are never clicked.
You will need to add CSS property pointer-events:none to your canvas.
#myCan {
...
pointer-events: none;
}
This way it won't block table from being clicked anymore.
You can also add event listeners to your cells way simpler:
document.querySelectorAll('#myTable td')
.forEach(e => e.addEventListener("click", function() {
// Here, `this` refers to the element the event was hooked on
console.log("clicked")
}));
That creates a separate function for each cell; instead, you could share one function without losing any functionality:
function clickHandler() {
// Here, `this` refers to the element the event was hooked on
console.log("clicked")
}
document.querySelectorAll('#myTable td')
.forEach(e => e.addEventListener("click", clickHandler));
Some browsers still don't have forEach on the HTMLCollection returned by querySelectorAll, but it's easily polyfilled:
if (!HTMLCollection.prototype.forEach) {
Object.defineProperty(HTMLCollection.prototype, "forEach", {
value: Array.prototype.forEach
});
}
If you have to support truly obsolete browsers that don't have Array.prototype.forEach, see the polyfill on MDN.
This is a case for event delegation: Hook the click event on the table (or table body), not individual cells, and then determine which cell was clicked by looking at event.target and its ancestors.
Simplified example:
document.querySelector("#my-table tbody").addEventListener("click", function(event) {
var td = event.target;
while (td !== this && !td.matches("td")) {
td = td.parentNode;
}
if (td === this) {
console.log("No table cell found");
} else {
console.log(td.innerHTML);
}
});
Live Copy:
document.querySelector("#my-table tbody").addEventListener("click", function(event) {
var td = event.target;
while (td !== this && !td.matches("td")) {
td = td.parentNode;
}
if (td === this) {
console.log("No table cell found");
} else {
console.log(td.innerHTML);
}
});
table, td, th {
border: 1px solid #ddd;
}
table {
border-collapse: collapse;
}
td, th {
padding: 4px;
}
<table id="my-table">
<thead>
<tr>
<th>First</th>
<th>Last</th>
</tr>
</thead>
<tbody>
<tr>
<td>Joe</td>
<td>Bloggs</td>
</tr>
<tr>
<td>Muhammad</td>
<td>Abdul</td>
</tr>
<tr>
<td>Maria</td>
<td>Gonzales</td>
</tr>
</tbody>
</table>
Note that instead of the loop you could use the new (experimental) closest method on elements:
var td = event.target.closest("td");
...but A) It's still experimental, and B) It won't stop when it reaches the tbody, so in theory if you had nested tables, would find the wrong cell.
If you need to support browsers that don't have Element.prototype.matches, in this specific case you could use td.tagName !== "TD" instead of !td.matches("td") (note the capitalization).
Using only the DOM objects
Here's an example cell wise event listener added on an HTML table (TicTacToe). It can be achieved easily using 'this' keyword and 'querySelectorAll'
The logic is in the JavaScript file:
First, get all the cells by their 'tag' ("td") using 'querySelectorAll' and save it as a list
Add an event listener to each of the cells, and give a function name to do whatever you want
Inside the event listener function, using this keyword update the cell content, or call other functions or do whatever task you have to complete.
var cells = document.querySelectorAll("td");
for (var cell of cells) {
cell.addEventListener('click', marker)
}
function marker() {
if (this.textContent === 'X') {
this.innerHTML = "O";
} else if (this.textContent === 'O') {
this.innerHTML = " ";
} else {
this.innerHTML = "X";
}
}
td {
text-align: center;
font-size: 50px
}
table,
th,
td {
border: 2px solid black;
width: 300px;
height: 100px;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Tic Tac Toe</title>
</head>
<body>
<table id="ticTac">
<tbody>
<tr>
<td>. </td>
<td>. </td>
<td>. </td>
</tr>
<tr>
<td>. </td>
<td>. </td>
<td>. </td>
</tr>
<tr>
<td>. </td>
<td>. </td>
<td>. </td>
</tr>
</tbody>
</table>
</body>
</html>

How to perform input fields validation and to prevent from adding new row if the fields are empty?

I have a simple table with three input fields (text, date and dropdown) and on click of an "add row" button, new row is getting added. However I need to perform below validation on the input fields; the new row should not get added if the input fields are empty and it should throw an error message. How to achieve that?
Functions to add new row and to delete selected row:
function addRow(tableID) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var colCount = table.rows[0].cells.length;
for (var i = 0; i < colCount; i++) {
var newcell = row.insertCell(i);
newcell.innerHTML = table.rows[0].cells[i].innerHTML;
//alert(newcell.childNodes);
switch (newcell.childNodes[0].type) {
case "text":
newcell.childNodes[0].value = "";
break;
case "checkbox":
newcell.childNodes[0].checked = false;
break;
case "select-one":
newcell.childNodes[0].selectedIndex = 0;
break;
}
}
}
function deleteRow(tableID) {
try {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
for (var i = 0; i < rowCount; i++) {
var row = table.rows[i];
var chkbox = row.cells[0].childNodes[0];
if (null != chkbox && true == chkbox.checked) {
if (rowCount <= 1) {
alert("Cannot delete all the rows.");
break;
}
table.deleteRow(i);
rowCount--;
i--;
}
}
} catch (e) {
alert(e);
}
}
body {
font-family: "Open Sans", Helvetica, Arial, sans-serif;
font-weight: 300;
font-size: 12px;
line-height: 30px;
color: #777;
background: #366161;
}
#dataTable {
margin: 0 auto;
margin-top: 30px;
}
.btn {
-webkit-border-radius: 5;
-moz-border-radius: 5;
border-radius: 5px;
font-family: Arial;
color: #ffffff;
font-size: 15px;
background: #2f354a;
padding: 7px 15px 7px 15px;
text-decoration: none;
outline: none;
margin: 30px;
}
.btn:hover {
background: #3cb0fd;
text-decoration: none;
}
.btn_container {
margin: 0 auto;
width: 360px;
}
select option[value="red"] {
background-color: #f00;
}
select option[value="yellow"] {
background-color: #FFFF00;
}
select option[value="green"] {
background-color: #7CFC00;
}
h1.heading {
text-align: center;
color: #ffffff;
}
#errors {
margin-left: 310px;
color: red;
font-size: 16px;
}
<body>
<h1 class="heading"> Simple Form</h1>
<table id="dataTable" width="900px" cellspacing="5" cellpadding="10" style="background:#F0F8FF;border:1px dotted">
<tr>
<td><input type="checkbox" name="chk" /></td>
<td> Name : <input type="text" name="txt" id="fname" placeholder="Enter your name" required/></td>
<td>Date: <input type="date" name="date" id="delivery_date" required/></td>
<td>
Color:
<select name="Color" required>
<option value="red">Red</option>
<option value="yellow">yellow</option>
<option value="green">Green</option>
</select>
</td>
</tr>
</table>
<div class="btn_container">
<input type="button" class="btn" value="Add Row" onclick="addRow('dataTable')" />
<input type="button" class="btn" value="Delete Row" onclick="deleteRow('dataTable')" />
</div>
</body>
This code will check the previous row and, if either the name or date field of that row is empty, a new row won't be added. The alert displays, "Please fill the current row in before adding a new row" but you change the message to anything you like.
var prevName = table.rows[rowCount - 1].cells[1].firstChild.nextSibling.value;
var prevDate = table.rows[rowCount - 1].cells[2].firstChild.nextSibling.value;
if (prevName == "" || prevDate == "") {
alert("Please fill the current row in before adding a new row");
return;
}
Insert it after this line:
var rowCount = table.rows.length;
and before this line:
var row = table.insertRow(rowCount);

Categories

Resources