JavaScript Save Table Rows added by User - javascript

I am making an Electron app that has tables, the user can add a table and change the content of the fields, but I want the input to be saved, and only if the user entered anything into them.
How would I do this? Do I need a database? Can it be done with cookies? I have tried to learn how to use cookies but have not found how to save an added element as well as the content.
function appendRow(id) {
var table = document.getElementById(id); // table reference
length = table.length,
row = table.insertRow(table.rows.length); // append table row
var i;
// insert table cells to the new row
for (i = 0; i < table.rows[0].cells.length; i++) {
createCell(row.insertCell(i), i, 'row');
}
}
function createCell(cell, text, style) {
var div = document.createElement('div'), // create DIV element
txt = document.createTextNode('_'); // create text node
div.appendChild(txt); // append text node to the DIV
div.setAttribute('id', style); // set DIV class attribute
div.setAttribute('idName', style); // set DIV class attribute for IE (?!)
cell.appendChild(div); // append DIV to the table cell
}
table {
text-align: center;
width: 400px;
}
tr:nth-child(even) {
background-color: #ccc;
}
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<link rel="stylesheet" href="test.css">
</head>
<body>
<button id="addCust" class="addSort" onclick="appendRow('custList')">add customer</button>
<table id="custListTop" contenteditable="false" style="background-color: #ccc;">
<tr>
<td style="border-top-left-radius: 5px;">Customers</td>
<td style="border-top-right-radius: 5px;">Main Location</td>
</tr>
</table>
<table id="custList" contenteditable="true">
<tr>
<td>Someone</td>
<td>something</td>
</tr>
</table>
<script src="test.js"></script>
</body>
</html>

Well how you are going to save it depends on what you want to do. If you want it to persist after your program was exited, you will need to save it on the disk or on a server somehow. You probably just want to save it into a file, though. (JSON is the most obvious choice). Otherwise, just save it into a js variable.
To get the data, I would either use a save button that reads the text of your cells, or use databinding. Later is very useful for Electron apps. You can either use a framework (like vue.js, react.js or many more) or DIY.
Former is probably easier and you will want a button to save it to the disk anyways. On the click of the button you can just go through all <tr>-elements and get their values and save them.
function save(id) {
var table = document.getElementById(id);
var trs = table.getElementsByTagName('tr'); // list of all rows
var values = []; // will be a (potentially jagged) 2D array of all values
for (var i = 0; i < trs.length; i++) {
// loop through all rows, each will be one entrie in values
var trValues = [];
var tds = trs[i].getElementsByTagName('td'); // list of all cells in this row
for (var j = 0; j < tds.length; j++) {
trValues[j] = tds[j].innerText;
// get the value of the cell (preserve newlines, if you don't want that use .textContent)
}
values[i] = trValues;
}
// save values
console.log(values);
}
function appendRow(id) {
var table = document.getElementById(id); // table reference
length = table.length,
row = table.insertRow(table.rows.length); // append table row
var i;
// insert table cells to the new row
for (i = 0; i < table.rows[0].cells.length; i++) {
createCell(row.insertCell(i), i, 'row');
}
}
function createCell(cell, text, style) {
var div = document.createElement('div'), // create DIV element
txt = document.createTextNode('_'); // create text node
div.appendChild(txt); // append text node to the DIV
div.setAttribute('id', style); // set DIV class attribute
div.setAttribute('idName', style); // set DIV class attribute for IE (?!)
cell.appendChild(div); // append DIV to the table cell
}
table {
text-align: center;
width: 400px;
}
tr:nth-child(even) {
background-color: #ccc;
}
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<link rel="stylesheet" href="test.css">
</head>
<body>
<button id="addCust" class="addSort" onclick="appendRow('custList')">add customer</button>
<button id="save" class="save" onclick="save('custList')">save</button>
<table id="custListTop" contenteditable="false" style="background-color: #ccc;">
<tr>
<td style="border-top-left-radius: 5px;">Customers</td>
<td style="border-top-right-radius: 5px;">Main Location</td>
</tr>
</table>
<table id="custList" contenteditable="true">
<tr>
<td>Someone</td>
<td>something</td>
</tr>
</table>
<script src="test.js"></script>
</body>
</html>

Related

How to select each row and highlight / unselect each row and highlight from data api call

This is my table on start
<div class= "col-md-7" id = "recyclable-list" >
<table class="table">
<thead>
<tr>
<th style=" padding-left:25px;";>RecyclableID</th>
<th style=" padding-left:100px;">Name</th>
<th style=" text-align: center;">RecyclableType</th>
</tr>
</thead>
<tbody id="recycleTable">
</tbody>
</table>
This is my script call for database
var myarray = [];
$.ajax({
url:"https://ecoexchange.dscloud.me:8080/api/get",
method:"GET",
// In this case, we are going to use headers as
headers:{
// The query you're planning to call
// i.e. <query> can be UserGet(0), RecyclableGet(0), etc.
query:"RecyclableGet(0)",
// Gets the apikey from the sessionStorage
apikey:sessionStorage.getItem("apikey")
},
success:function(data,xhr,textStatus) {
myarray = data;
buildTable(myarray);
console.log(myarray);
},
error:function(xhr,textStatus,err) {
console.log(err);
}
});
function buildTable(data){
var table = document.getElementById("recycleTable")
for(var i = 0; i < data.length; i++){
var row = `<tr>
<td>${data[i].RecyclableID}</td>
<td>${data[i].Name}</td>
<td>${data[i].RecyclableType}</td>
</tr>`
table.innerHTML += row
}
};
This is my hightlight Js file
$( document ).ready(function() {
$("#recyclable-list").on('click',function() {
var selected = $('#recycleTable tr').on('click',async function(){
await $('#recycleTable tr').removeClass('highlight');
$(this).addClass('highlight');
});
$("#edit").prop('disabled',false);
$("#edit").removeClass('btn btn-secondary');
$("#edit").addClass('btn btn-primary');
$("#delete").prop('disabled',false);
if (!selected)
$(this).find('#recycleTable tr').addClass("highlight") & $('#recycleTable tr').removeClass('highlight');
else
$("#edit").prop('disabled',true) & $("#delete").prop('disabled',true) & $("#edit").removeClass('btn btn-primary') & $("#edit").addClass('btn btn-secondary');;
});
});
and this is my css style for highlight
.recycleTable.highlight{
background-color: #ddd;
}
But however the highlight now is selecting the whole table row instead of row by row, does anyone have any idea how to i change it to select row per row instead of the the whole row ?
Now the selected whole table have been fix but however i am unable to unselect the row i choose and button is not enabled when selected a row
Click event on tbody? not a good idea, i suggest you to change your code to this :
...
$("#recyclable-list").on('click',function() {
var selected = $(this).find('#recycleTable').hasClass("highlight");
...
if (!selected)
$(this).find('#recycleTable').addClass("highlight");
...
Update
Dynamically added <tr> must have the "click" event delegated to a parent element that's been there since the DOM was loaded (ie hard coded in HTML). In this case the <tbody> is a good canident. One extra parameter is needed:
/*
'tr' delegates click events to any <tr> within
the <tbody> whether static or dynamic.
*/
$('tbody').on('click', 'tr', function(e) {...
First of all, never use #id, use class, otherwise you have hindered your code -- that's especially true if you are using jQuery. #id is useful in circumstances such as Bootstrap plugins, but not much else. The example below uses only classes.
This will allow only a single <tr> to be highlighted and also removes highlighting if the <tr> was already highlighted.
$('tbody tr').not($(this)).removeClass('highlight');
$(this).toggleClass('highlight');
This will disable the <button>s if there's a highlighted <tr>
const btns = $('.btn-group button');
...
if ($(this).hasClass('highlight')) {
btns.prop('disabled', false).removeClass('disabled dark');
} else {
btns.prop('disabled', true).addClass('disabled dark');
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<style>
.highlight {
background-color: #ddd;
}
button {
display: inline-block;
width: 100px;
}
.dark {
background-color: #000;
color: #666;
}
</style>
</head>
<body>
<main class="fluid-container">
<fieldset class='btn-group'>
<button class='add btn btn-success'>Add Row</button>
<button class='dark edit btn btn-primary disabled change-row' disabled>Edit</button>
<button class='type btn btn-warning'>Add Type</button>
<button class='dark delete btn btn-danger disabled change-row' disabled>Delete</button>
</fieldset>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>User Name</th>
<th>Email</th>
</tr>
</thead>
<tbody></tbody>
</table>
</main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script>
const buildTable = data => {
const table = document.querySelector('.table tbody');
for (let i = 0; i < data.length; i++) {
let row = `<tr>
<td>${data[i].name}</td>
<td>${data[i].username}</td>
<td>${data[i].email}</td>
</tr>`;
table.insertAdjacentHTML('beforeEnd', row);
}
};
const getData = async(url) => {
const response = await fetch(url);
const json = await response.json();
return buildTable(json);
};
getData('https://jsonplaceholder.typicode.com/users/');
$(document).ready(function() {
const btns = $('.change-row');
$("tbody").on('click', 'tr', function(e) {
/* //Add this line if you want only a single row selected
$('tbody tr').not($(this)).removeClass('highlight');
*/
$(this).toggleClass('highlight');
if ($('tbody tr').hasClass('highlight')) {
btns.prop('disabled', false).removeClass('disabled dark');
} else {
btns.prop('disabled', true).addClass('disabled dark');
}
});
});
</script>
</body>
</html>
You care calling id but your declaration is a class. Change from . to # as in #recycleTable.highlight

Save content editable HTML table in multiple fields

I need to develop a HTML table where one of the table column is editable on its row and the table row is dynamic in term of the row number.
I come across a problem where when I automate the saveEdits() function, the code is not working.
Here is my code, where the 'cnt' is a dynamic numeric number. Example cnt=50
<!DOCTYPE html>
<html>
<head>
<style>
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
table ,tr td{
border:1px solid #dddddd;
padding: 8px;
}
tbody {
display:block;
height:600px;
overflow:auto;
}
thead, tbody tr {
display:table;
width:100%;
table-layout:fixed;
}
thead {
width: calc( 100% - 1em )
}
tr:nth-child(even) {
background-color: #dddddd;
}
</style>
<script type="text/javascript">
function saveEdits(cnt) {
//get the editable elements.
var str_out = ''
while (cnt>0){
str1 = '\'edit' + cnt + '\': document.getElementById(\'edit' + cnt + '\').innerHTML,\n'
str_out = str_out.concat(' ', str1);
cnt--;
};
var editElems= { str_out };
alert(editElems)
//save the content to local storage. Stringify object as localstorage can only support string values
localStorage.setItem('userEdits', JSON.stringify(editElems));
}
function checkEdits(){
//find out if the user has previously saved edits
var userEdits = localStorage.getItem('userEdits');
alert(userEdits) // suppose to print {"edit1":" rpeyy7<br>","edit2":" tpruiiy<br>","edit3":" opty<br>"}
if(userEdits){
userEdits = JSON.parse(userEdits);
for(var elementId in userEdits){
document.getElementById(elementId).innerHTML = userEdits[elementId];
}
}
}
</script>
</head>
<body onload="checkEdits()">
<table id="myTable">
<thead>
<tr>
<td style="background-color:#A9A9A9" > Field#1 </td>
<td style="background-color:#A9A9A9" > Field#2 </td>
<td style="background-color:#A9A9A9" > Field#3- Each Row Under field#3 is content EditableByUser </td>
</tr>
</thead>
<tbody>
// Here is the python code that loop through a diectionary content
cnt = 0
for c in sorted(data_dict.keys()) :
cnt += 1
<tr>
<td> {0} </td> //Field#1
<td> {0} </td> //Field#2
...
...
<td id="edit{0}" contenteditable="true" onKeyUp="saveEdits({0});"> {1} </td>\n'.format(cnt,comment)]
</tr>
</table>
</body>
I'm not sure where goes wrong as when I automate the saveEdits() function with 'cnt' in while loop, the above code doesn't works for me. But when I defined each row clearly like below, the data the keyed-in are properly saved to each column.
function saveEdits(cnt) {
//get the editable elements.
var editElems = {
'edit1': document.getElementById('edit1').innerHTML,
'edit2': document.getElementById('edit2').innerHTML,
'edit3': document.getElementById('edit3').innerHTML,
};
alert(editElems) //print [object Object]
//save the content to local storage. Stringify object as localstorage can only support string values
localStorage.setItem('userEdits', JSON.stringify(editElems));
}
I would be much appreciate if someone can point out my mistake. The error is very much likely on saveEdits(cnt) function but I'm not sure how to fix that cause it I define each count 1 by 1, each update that being keyed-in is actually saved properly and able to retrieve when rerun. Thanks you!

Javascript Dynamic Table with each cell having an onmouse event?

I've created a dynamic table using Javascript. Now what I'm trying to do is for each cell that is dynamically generated, there is an onmouseover event that would change that particular cell's backgroundColor.
The problem I have is that when I generate the table and try to have an onmouseover function with each dynamically generated cell the function only works for the last generated cell.
Here's a copy of my code. (Note: I have only tested this on Chrome)
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
padding: 5px;
text-align: center;
}
</style>
<script type="text/javascript">
var table;
function init(){
table = document.getElementById("mytable");
}
function makeCells(){
init();
for(var a=0;a<20;a++){
var row = table.insertRow(-1);
for(var b=0;b<20;b++){
cell = row.insertCell(-1);
cell.innerHTML = a*b;
cell.onmouseover = function(){cell.style.backgroundColor = "yellow";};
}
}
}
</script>
</head>
<body onload="javascript: makeCells();">
<table id="mytable"></table>
</body>
</html>
Any advice would be greatly appreciated.
Some Improvements. 3 things I would change:
Don't edit inline styles with javascript. Instead, add or remove a class. see # 3.
Don't do so many event handlers in your "onload", "onmouseover". Its better to add an event listener.
It is better performance to add all of the new elements at one time instead of individually. See this article: https://developers.google.com/speed/articles/reflow
Here is a way to optimize the Javascript:
HTML
<table id="table"></table>
CSS
body {
padding: 40px;
}
.yellow {
background: yellow;
}
td {
padding: 10px 20px;
outline: 1px solid black;
}
JavaScript
function propegateTable() {
var table = document.getElementById("table");
//will append rows to this fragment
var fragment = document.createDocumentFragment();
for(var a=0; a<10; a++){ //rows
//will append cells to this row
var row = document.createElement("tr");
for(var b=0;b<5;b++){ //collumns
var cell = document.createElement("td");
cell.textContent = a + ", " + b;
// event listener
cell.addEventListener("mouseover", turnYellow);
row.appendChild(cell);
}
fragment.appendChild(row);
}
//everything added to table at one time
table.appendChild(fragment);
}
function turnYellow(){
this.classList.add("yellow");
}
propegateTable();
http://codepen.io/ScavaJripter/pen/c3f2484c0268856d3c371c757535d1c3
I actually found the answer myself playing around with my code.
In the line:
cell.onmouseover = function(){cell.style.backgroundColor = "yellow";};
I changed it to:
cell.onmouseover = function(){this.style.backgroundColor = "yellow";};

Hide column while exporting to excel from html table using javascript

I have a html table which I have to export to excel , but while doing so, I dont want some of the td elements to be exported. When I apply javascript to hide the td, the changes are being applied only to the view form and not to the the content being exported.
Need help in how to export in this case.
I have included html, css and script all in one page.
<html>
<body>
<div id="myDiv">
<table id="metrics" border="1px" cellspacing="0 px" style="border-style: solid; border-color: Black;
border-width: thin;">
<tr>
<td style= "background-color: #bfbfbf; font-size: small; color: black;">
LOB
</td>
<td>
<span class="hillbillyForm" data-displayname='LOB' style="display:none;"></span>
</td>
</tr>
</table>
<input type="button" id="btnExport" value="Export" onclick="TableToExcel('metrics');" />
</div>
</body>
Here I want to hide the td which contains span class "hillbillyForm"
The javascript That I am using is
function TableToExcel(tableid) {
var id = $('[id$="' + tableid + '"]');
var $clonedTable = $("id").clone();
$clonedTable.find('[style = "display: none"]').remove();
var strCopy = $('<div></div>').html(id.clone()).html();
window.clipboardData.setData("Text", strCopy);
var objExcel = new ActiveXObject("Excel.Application");
objExcel.visible = false; var objWorkbook = objExcel.Workbooks.Add; var objWorksheet = objWorkbook.Worksheets(1); objWorksheet.Paste; objExcel.visible = true;
}
</script>
So what I'm understanding is that you want to remove all TD's which have a direct child with the class hillbillyForm.
You can do something like this:
var form = document.getElementById(tableid),
exportForm = form.cloneNode(true),
elementsToRemove = exportForm.querySelectorAll('.hillbillyForm');
for (var i = elementsToRemove.length; i--;){
var td = elementsToRemove[i].parentElement;
if (td) td.parentElement.removeChild(td);
}
jsFiddle

Add event listener by class, pass ID as argument in JS

I have a grid set up of days of the week by times of the day, each slot on the grid is a checkbox for my site's users to indicate availability. Since this ends up being a large number of slots, I would like for the background color of the slot to change depending on whether it is checked or not, but again due to the large number of slots I don't want to have to add an event listener for each ID. Is it possible to add a single listener for the class and pass the ID of the clicked element so only its background is changed?
You'll have to use event delegation to accomplish this, simple example
document.addEventListener('change', function(e){alert(e.target.id)});
http://jsfiddle.net/mowglisanu/cCFxQ/
Assuming that your checkboxes are the childNodes of your <td> elements, you can use this code:
var checkedList = document.getElementsByClassName('checked');
for(var i = 0; i < checkedList.length; i++) {
var current = checkedList[i],
parent = current.parentNode; //it is the td
if (current.checked) parent.style.backgroundColor = 'color';
}
Working JSFiddle
If you want it to be completely dynamic, you should add an event listener as Musa said.
document.addEventListener('change', function(e){
var current = e.target,
parent = current.parentNode;
if (current.checked) parent.style.backgroundColor = 'color';
});
here a logic that should fix ur problem.
i will suggest of using a some framework "jquery" for easy work
var checkedList = document.getElementsByClassName('checkboxes');
checkedList.addEventListener('change', function(e){
var node = e.target;
if(node.checked){
node.parentElement.style.background-color='grey';
}else{
node.parentElement.style.background-color='white';
}
});
I used the following code to solve the problem you had.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">.lw {
border: 1px solid red;
font-size: 60px;
}
tr td{
border: 1px solid red;
width: 40px;
height: 40px;
}</style>
<title>HTML5, CSS3 and JavaScript demo</title>
</head>
<body>
<!-- Start your code here -->
<div>
<table class="gameboard">
<tbody>
<tr>
<td class="slot" id="One">x</td>
<td class="slot" id="Two"></td>
<td class="slot" id="Three"></td>
</tr>
<tr>
<td class="slot" id="Four"></td>
<td class="slot" id="Five"></td>
<td class="slot" id="Six"></td>
</tr>
<tr>
<td class="slot" id="Seven"></td>
<td class="slot" id="Eight"></td>
<td class="slot" id="Nine"></td>
</tr>
</tbody></table>
</div>
<div>
<p id="titleOf" class="lw">Hello Weaver!</p>
</div>
<!-- End your code here -->
<script>/* Write JavaScript here */
var a = document.getElementById("titleText");
var b = document.getElementById("titleOf");
var c = document.getElementsByClassName("gameboard");
var piece = document.getElementsByClassName('slot');
var Gamelogic = {
checkFirst:false,
makeX: function(e){
for(var i= 0; i< piece.length - 1; i++){
if(e.path[i]){
e.path[0].innerText = "X";
e.path[0].style.backgroundColor = "green" ;
console.log(e.path);
console.log(e.path[0]);
console.log(e.path[i]);
}
break;
}
}
};
c[0].addEventListener("click", Gamelogic.makeX); // if the table is clicked
</script>
</body>

Categories