Creating a table through local storage data? - javascript

How can I populate my table with an array of local storage data?
function savePlayer() {
let Player = {player,score};
localStorage.setItem("Player", JSON.stringify(Player));
let getPlayerScore = Player;
let text = document.getElementById("topScores");
for(let i = 0; i <Player.length; i++){
text += "<tr>";
text += "<td>" + getPlayerScore[i].player + "</td>";
text += "<td>" + getPlayerScore[i].score + "</td></tr>";
}
Here's the HTML:
<body>
<table id = "topScores">
<tr>
<th>Username</th>
<th>Score</th>
</tr>
</table>
</body>
What am I doing wrong?

The Player.toString() isn't what you think it is.
var player = "Mario";
var score = 1000;
var Player = {
player,
score
};
// Print Player
console.log(JSON.stringify(Player));
console.log(Player.toString());

You can't just add text to an element; you need to set it though
innerHTML. Sadly, however, you can't set it for each row, because the DOM will try to end the tr tag, so you need to set everything at the same time through a string.
I couldn't get localStorage to work in the snippet so I commented out the code without testing it.
Another solution would be to append the elements, and honestly, that's what I would prefer, but I didn't want to steer to far away from your original solution, and I didn't want fix the "feature" where the DOM is autocompleting tr tags.
function savePlayer() {
// This wasn't an array to begin with, so I fixed that.
let Player = [{"player": "player","score": 10}];
// It's usually preferred to refer to a public constant when accessing localStorage.
let localStorageKey = "player";
/* localStorage.setItem(localStorageKey, JSON.stringify(Player));
let getPlayerScore = JSON.parse(localStorage.getItem(localStorageKey));*/
let getPlayerScore = Player;
let text = document.getElementById("topScores");
var playerRow = "";
for(let i = 0; i < getPlayerScore.length; i++){
playerRow = "<tr>";
playerRow += "<td>" + getPlayerScore[i].player + "</td>";
playerRow += "<td>" + getPlayerScore[i].score + "</td></tr>";
}
text.innerHTML += playerRow;
}
<body onload="savePlayer()">
<table id="topScores">
<tr>
<th>Username</th>
<th>Score</th>
</tr>
</table>
</body>

Related

Create new <tr>as text after 3rd <td> in JS

i want to create new table row as text <tr> after every third table data<td> from user input.
It have to be like this:
<table border="3" align="center" style="width: 100%;">
<tr>
<td><a href="link"><img src="link"></td>
<td><a href="lin"><img src="link"></td>
<td><a href="link"><img src="link"></td>
</tr>
<tr>
<td><a href="link"><img src="link"></td>
<td><a href="lin"><img src="link"></td>
<td><a href="link"><img src="link"></td>
</tr>
</table>
My code:
<script type="text/javascript">
let x = 0;
const data = Array();
document.getElementById('btn').addEventListener("click", fun);
function fun() {
var val = document.getElementById('imagename').value;
source = val;
img = document.createElement('img');
img.src = source;
document.body.appendChild(img);
// move child to up
var before = document.getElementById('before');
before.insertBefore(img, before.children[0]);
/*var html = document.getElementById('before').innerHTML;
document.getElementById('code').innerHTML = '<img src=' + src + '>';*/
document.getElementById('code').innerText = '<img src="' + source + '">';
data[x] = document.getElementById('imagename').value;
x++;
}
document.getElementById('pasteBtn').addEventListener("click", makeCode);
function makeCode(){
let resultData = "<tr>";
for (let i = 0; i < data.length; i++){
resultData += "<td>" + '<a href="' + data[i] + '">' + '<img src="' + data[i] + '"></td>\n';
if(i % 3 == 0){
resultdata += '</tr><tr>';
}
}
cssText = 'tr {width: 100%; display: flex;} td {width: 100%;}';
tableText = '\n<table border="3" align="center" style="width: 100%;">\n';
document.getElementById("paste").innerText = "<style>" + cssText + "</style>" + tableText + resultData;
}
</script>
I was trying with modulo but nothing happened. It have to be done in JS, not JQuery.
Your code has a couple of problems, which have been mentioned in the comments. The last created row is not closed. Some browsers nowadays automatically solve this problem by adding the closing tag for that row, but it leaves you with a floating row.
A second problem is your modulo calculation. Since javascript arrays start at 0 and not at 1 you modulo creates the row to early, for:
0 % 3 = 0
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
A row is created containing ONLY the first value. This can be fixed by changing the modulo calculation to i + 1 % 3, however it might not immediatly be clear why you seemingly randomly add the 1.
Another option is to introduce a counter. It is clear what the counter does, it counts. It is also clear to where it counts, 3. By moving the closing and starting of the row to before the adding of the cell you prevent floating rows. You only start a new row, when you actually need one. Important still is to close the row, but as said before, there are browsers that do this, but you should not rely on that.
let resultData = "<tr>";
let counter = 0;
for (let i in data){
if(counter == 3){
resultdata += '</tr><tr>';
counter = 0;
}
resultData += "<td>" + '<a href="' + data[i] + '">' + '<img src="' + data[i] + '"></td>\n';
counter++;
}
resultdata += "</tr>";
Personally I prefer to use a for...in loop for looping over an array, but that is personal preference
There are many ways to accomplish what you are looking for.
For my answer I chunked the array into groups of 3, then I loop through each element in each group.
I also chose to use createElement instead of using the string versions.
let table = document.querySelector("#paste");
let data = [
1,2,3,4,5,6,7,8,9
];
while((row = data.splice(0, 3)).length){
let tr = document.createElement("tr");
for(z=0;z<=row.length-1;z++){
let td = document.createElement("td");
let link = document.createElement("a");
let img = document.createElement("img");
img.src = row[z];
link.href = row[z];
link.appendChild(img)
td.appendChild(link)
tr.appendChild(td)
}
table.appendChild(tr)
}
<table id="paste"></table>
Adding EventListener to MakeCode.Btn.getting the count of td each row has with data.length/3(9/3=3);so each row will have 3 td's.
Creating index variable to iterate over the array.
creating Two ForLoops.
1st loop will create a row with an id of r(i).first row will have an id of id="r1".
2nd loop will get the row that was created in the first loop and it will add td tCount times which is 3 in this case.
& data will also be added inside each td with ${data[index]}
incrementing the index every time a td is added.
when index is equal to data.length getting the innerHtml of the table and pasting it in the text area as a value.and setting the innerHtml of the actual table to "" empty
const data = [
"hello",
"world",
"code",
"coding",
"javascript",
"css",
"html",
"react",
"scss"
];
let table = document.getElementById("table");
let btn = document.getElementById("pasteBtn");
let textBox = document.getElementById("textbox");
btn.addEventListener("click", () => {
let tdCount = data.length / 3;
let index = 0;
for (let i = 1; i <= 3; i++) {
table.innerHTML += `<tr id="r${i}"></tr>`;
for (let j = 1; j <= tdCount; j++) {
document.getElementById(`r${i}`).innerHTML += `<td><a href="link"><img src="link"></td>`;
index++;
if (index === data.length) {
let finalHtml = document.getElementById("table").innerHTML;
textBox.value = finalHtml;
document.getElementById("table").innerHTML = "";
}
}
}
});
textarea {
width: 100%;
height: 200px;
}
<button id="pasteBtn">makeCode</button>
<table border="3" align="center" style="width: 100%;">
<tbody id="table">
</tbody>
</table>
<textarea id="textbox"></textarea>
As mentioned #imvain2's answer, it is better to use js document.createElement over the string to create the elements. And here is an approach that uses a single loop.
HTML:
<table id="data-table"></table>
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const table = document.getElementById('data-table');
const addRows = (data) => {
let tableRow = null;
data.forEach((item, index) => {
// adds a new row on first and then after every third "td"
if (index % 3 === 0) {
tableRow = document.createElement('tr');
tableRow.id = 'tr' + (index + 1);
table.appendChild(tableRow);
}
const tableData = document.createElement('td');
tableRow.appendChild(tableData);
const link = document.createElement('a');
link.href = item;
link.title = item;
tableData.appendChild(link);
const img = document.createElement('img');
img.src = item;
link.appendChild(img);
});
};
addRows(data);

Google sheets script - Unable to get background color from cells that are part of pivot table

I have written the following code which replicates a Google Sheets pivot table in HTML along with the formatting to send out in an email.
issue: getBackgrounds() does not return the colours of the cells of the pivot table (it always returns #FFFFF). I verified the range to be correct, because the table is rendered with the correct amount of rows and columns along with the data values. However without styling. Further, if the colour of a cell is changed manually in the Sheets UI before running the script, then getBackgrounds() will fetch that colour. How can I retrieve the formatting of the pivot table?
code:
function getData(){
let ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("TCD").getRange(5,1).getDataRegion();
let background = ss.getBackgrounds();
let val = ss.getDisplayValues();
let fontColor = ss.getFontColors();
let fontStyles = ss.getFontStyles();
let fontWeight = ss.getFontWeights();
let fontSize = ss.getFontSizes();
return [val,background,fontColor,fontStyles,fontWeight,fontSize];
}
function setupEmail(attachment, sendBool) {
let ss_data = getData();
let data = ss_data[0];
let background = ss_data[1];
let fontColor = ss_data[2];
let fontStyles = ss_data[3];
let fontWeight = ss_data[4];
let fontSize = ss_data[5];
html += "<table border='1' style=\"background-color:#000000;\">";
for (let i = 0; i < data.length; i++) {
html += "<tr>"
for (let j = 0; j < data[i].length; j++) {
html += "<td style=\"height:20px;background-color:" + background[i][j] + "; color: " + fontColor[i][j] + "; font-style: " + fontStyles[i][j] + "; font-weight: " + fontWeight[i][j] + "; font-size: " + (fontSize[i][j] + 6) + "px; text-align: center;\">" + data[i][j] + "</td>";
Logger.log(background[i][j]);
}
html += "</tr>";
}
html + "</table>"
EDIT: I have worked around this by hardcoding the background-color. If anyone knows why the background colors of a pivot table cannot be returned, please do contribute.

Using Firestore's snapshot.forEach to create a table

I'm trying to output an array filled with Firestore objects onto a table, but just displays the last object above the table
<table class="darkTable">
<thead>
<tr>
<th>List of Available Shows</th>
</tr>
</thead>
<tbody>
<tr>
<div id="showList"></div>
</tr>
</tbody>
</table>
<script>
firebase.firestore().collection('TV Shows').get().then(snapshot => {
var i = 0;
var array = [];
snapshot.forEach(doc => {
array[i] = doc.data().show.name;
//console.log(doc.data().show.name);
//showList.innerHTML = array[i] + "<br />";
showList.innerHTML = '<td>' + array[i] + '</td>';
i++;
});
});
</script>
Is it the way I'm going about the td code lines?
assuming this markup:
<div id="showList"></div>
then it works about like this:
firebase.firestore().collection('TV Shows').get().then(snapshot => {
var showList = document.getElementById('showList');
var html = '<table class="darkTable"><thead><tr>';
html += '<th>List of Available Shows</th>';
/* add further columns into here, alike the one above. */
html += '</tr></thead><tbody>';
snapshot.forEach(doc => {
html += '<tr>';
html += '<td>' + doc.data().show.name + '</td>';
/* add further columns into here, alike the one above. */
html += '</tr>';
});
html += '</tbody></table>';
showList.append(html);
});
You're resetting the entire showList element with every iteration of the loop:
showList.innerHTML = '<td>' + array[i] + '</td>';
I suspect you mean to append to it each time instead or resetting it entirely each time. Maybe try building a string with each iteration, then set the whole thing after the loop is over.

document.getElementById.innerHTML does not write anything ..?

My Problem:
document.getElementById("values").innerHTML does not write anything. If I try to do document.getElementById("values").innerHTML = "stuff"; (just with a String) - nothing happens.
What am I doing wrong here?
HTML:
<form onsubmit="save_entry();return false;">
<label for="i_km">Kilometer: <input type="text" name="km" id="i_km"></label><br>
<label for="i_fuel">Sprit: <input type="text" name="fuel" id="i_fuel"></label><br>
<input type="submit" value="Save" />
</form>
<div id="values"></div>
JavaScript:
function save_entry() {
var anzahl = localStorage.length/2;
var nameKeyKm = "k" + anzahl;
localStorage.setItem(nameKeyKm,document.forms[0]["km"].value);
var nameKeyF = "F" + anzahl;
localStorage.setItem(nameKeyF,document.forms[0]["fuel"].value);
document.write("Entry saved!")
}
function show_entry() {
document.getElementById("values").innerHTML = "<table><th>Kilometers</th><th>Tanked</th>";
for (var i = 0; i < localStorage.length/2; i++) {
alert("d");
var temp_km = "k"+i;
var temp_f = "F"+i;
document.getElementById("values").innerHTML = "<tr>";
document.getElementById("values").innerHTML = "<td>"+localStorage.getItem(temp_km)+"</td>";
document.getElementById("values").innerHTML = "<td>"+localStorage.getItem(temp_f)+"</td>";
document.getElementById("values").innerHTML = "</tr>";
}
document.getElementById("values").innerHTML = "</table>";
}
show_entry();
This does work!
function show_entry(){
var content = '';
content = content + '<table><th>Kilometer</th><th>Getankt</th>';
for(var i = 0; i < localStorage.length/2; i++)
{
var temp_km = "k"+i;
var temp_f = "F"+i;
content = content + "<tr>";
content = content + "<td>"+localStorage.getItem(temp_km)+"</td>";
content = content + "<td>"+localStorage.getItem(temp_f)+"</td>";
content = content + "</tr>";
}
content = content + "</table>";
document.getElementById("values").innerHTML = content;
}
innherHTML is an attribute, so everytime you write document.getElementById('id').innerHTML = '...' you are actually changing the value of innerHTML to that thing, not concatenating it.
So writing document.getElementById("values").innerHTML = "<table><th>Kilometers</th><th>Tanked</th>"' changes the value of innerHTML to "<table><th>Kilometers</th><th>Tanked</th>"', and, afterwards, you replaced this value for <tr>, then for <td>...</td> and so on...
You clearly want to create a table. Therefore, you should be concatenating the strings, using +=, like this:
function show_entry() {
document
.getElementById("values")
.innerHTML = "<table><th>Kilometers</th><th>Tanked</th>";
for(var i = 0; i < localStorage.length/2; i++)
{
var temp_km = "k"+i;
var temp_f = "F"+i;
document.getElementById("values").innerHTML += "<tr>";
document.getElementById("values").innerHTML += "<td>"+localStorage.getItem(temp_km)+"</td>";
document.getElementById("values").innerHTML += "<td>"+localStorage.getItem(temp_f)+"</td>";
document.getElementById("values").innerHTML += "</tr>";
}
document.getElementById("values").innerHTML += "</table>";
}
show_entry();
Each time you do
document.getElementById("values").innerHTML = "...";
you will replace the html inside the div with ID 'values'
So calling it multiple times with different values doesn't make sense.
You would either call it once and setting the whole innerHTML at once, like this
document.getElementById("values").innerHTML = "<tr><td>....etc...</td></tr>";
If you would call innerHTML sequentially you would do it as follows (which is just how to append any string in javascript), but in the comments below I just learned this should not be done like this:
document.getElementById("values").innerHTML += "<tr>";
document.getElementById("values").innerHTML += "<td>"+localStorage.getItem(temp_km)+"</td>";
document.getElementById("values").innerHTML += "<td>"+localStorage.getItem(temp_f)+"</td>";
document.getElementById("values").innerHTML += "</tr>";

Adding ending </tr> tags to an HTML strings within loop

I have an array of elements I would like to put into an HTML table:
var tags_arr = [1,2,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19];
I can make an HTML table by simply placing beginning <tr> tags every 4th iteration:
var checks = "<table border=1>";
for (var c = 0; c < tags_arr.length; c++){
if (c%4 == 0){
checks += "<tr>";
}
checks += "<td>" + tags_arr[c] + "</td>";
}
checks += "</table>";
$("body").append(checks);
JSBIN
However this solution relies on the browser to inject the closing <\tr> tag when it "sees" the new opening tag. The browser also seems not to care that the last row has fewer <td> cells than the previous rows do.
It works, but is there a way to make expand this so as not to completely rely on the browser. I've tried using a regex to inject them into the string, but it seems like there should be a way to do so in the loop. Is it feasible? Or since it only has to work in modern browsers, can I just rely on Chrome and Firefox to do the cleanup for me?
EDIT:
hacky regex way:
checks = checks.replace(/(<tr>)/g, "</tr><tr>").replace(/<\/tr>/, "");
checks += "</tr></table>";
The HTML5 spec explicitly tells us that it's not necessary to close <tr> and <td> tags in the obvious scenarios:
No need to close a <td> before the next <td> or <tr> or table block section (<tbody>, <tfoot>), or the </table> closing tag.
No need to close a <tr> before the next <tr>, block section, or table close.
I seriously doubt you'll run into modern browsers that won't do the right thing here. I bet even IE6 will do it properly.
You can simply append the TR closing tag before appending the starting TR tag:
for (var c = 0; c < tags_arr.length; c++){
if (c%4 == 0){
if (c !== 0) checks +="</tr>";
checks += "<tr>";
}
checks += "<td>" + tags_arr[c] + "</td>";
}
checks += "</tr></table>";
PS: Take care of the edge cases.
EDIT:
A more elgant solution is to distribute the items in arrays before hand:
var distributed = [];
var tags_arr = [1,2,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19];
while(tags_arr.length > 0) {
distributed.push(tags_arr.splice(0,4));
}
And then use some smart loops to create the html:
var html = distributed.reduce(function(html, item){
var td = item.reduce(function(html, item){
return html + '<td>' + item + '</td>';
}, '');
return html + '<tr>' + td + '</tr>';
}, '');
html = '<table border=1>' + html + '</table>';
for (var c = 0; c < tags_arr.length; c++){
if (c%4 == 0){
if (c > 0) {
checks += "</tr>";
}
checks += "<tr>";
}
checks += "<td>" + tags_arr[c] + "</td>";
}
if (c > 0) { // Don't add a closing tag if there were no rows at all
checks += "</tr>";
}
Just close the tr tag before opening one. If c == 0 no tag have been opened yet.
Don't forget to close the last tag after the for loop
var checks = "<table border=1>";
for (var c = 0; c < tags_arr.length; c++){
if (c%4 == 0){
if (c > 0)
checks += "</tr>"
checks += "<tr>";
}
checks += "<td>" + tags_arr[c] + "</td>";
}
if (tags_arr.length > 0)
checks += "</tr>"
var cell = 0, len = tags_arr.length;
for(var row = 0; cell < len; row++) {
checks += '<tr>';
for(var col = 0; col < 4 && cell < len; col++, cell++)
checks += '<td>' + tags_arr[cell] + '</td>';
checks += '</tr>';
}
The correct solution - no divisions, no exceptional cases, no extra memory.

Categories

Resources