My Sample JSON data looks something like:
the data fields are not the same set of fields for all my rows.
[{"date":"2020-04-05 18:26:01", "mydata":{"city":{"name":"paris"},"travel":{"frequency":"5","climate":"cold"}}},
{"date":"2020-04-05 18:26:17", "mydata":{"city":{"name":"amsterdam"},"fly":{"airports":"1","type":"international"}}}]
This is saved into a column in my MariaDB.
I want to retrieve this in a table format like:
Date mydata-city-name travel-frequency travel-climate fly-airports fly-type
2020-04-05 18:26:01 paris 5 cold null/blank null/blank
2020-04-05 18:26:17 amsterdam null/blank null/blank 1 international
so far i tried the below js and html
but im not able to get the data as expected:
Javascript:
var myList
$.ajax({
type: "GET",
url: "symptom_list.php",
success: function (data) {
console.log(data)
myList = JSON.parse(data)
console.log(JSON.parse(
data)
);
/* alert(data); */ // show response from the php script.
},
});
function buildHtmlTable(selector) {
var columns = addAllColumnHeaders(myList, selector);
for (var i = 0; i < myList.length; i++) {
var row$ = $('<tr/>');
for (var colIndex = 0; colIndex < columns.length; colIndex++) {
var cellValue = myList[i][columns[colIndex]];
if (cellValue == null) cellValue = "";
row$.append($('<td/>').html(cellValue));
}
$(selector).append(row$);
}
}
// Adds a header row to the table and returns the set of columns.
// Need to do union of keys from all records as some records may not contain
// all records.
function addAllColumnHeaders(myList, selector) {
var columnSet = [];
var headerTr$ = $('<tr/>');
for (var i = 0; i < myList.length; i++) {
var rowHash = myList[i];
for (var key in rowHash) {
if ($.inArray(key, columnSet) == -1) {
columnSet.push(key);
headerTr$.append($('<th/>').html(key));
}
}
}
$(selector).append(headerTr$);
return columnSet;
}
HTML:
<body onLoad="buildHtmlTable('#excelDataTable')">
<table id="excelDataTable" border="1">
</table>
</body>
My output is rightnow:
Date mydata
2020-04-05 18:26:01 <blank>
2020-04-05 18:26:17 <blank>
how do i get my expected output?
If you have nested data structure you also have to traverse in nested elements
function buildHtmlTable(selector) {
var columns = addAllColumnHeaders(myList, selector);
for (var i = 0; i < myList.length; i++) {
var row$ = $('<tr/>');
for (var colIndex = 0; colIndex < columns.length; colIndex++) {
var cellValue = getCellValue(myList[i], columns[colIndex]);
if (cellValue == null)
cellValue = "";
row$.append($('<td/>').html(cellValue));
}
$(selector).append(row$);
}
}
function addAllColumnHeaders(myList, selector) {
var columnSet = [];
var headerTr$ = $('<tr/>');
for (var i = 0; i < myList.length; i++) {
var rowHash = myList[i];
recursiveHeaderCheck(rowHash, selector, "", columnSet, headerTr$);
}
$(selector).append(headerTr$);
return columnSet;
}
function recursiveHeaderCheck(ListElement, selector, parentKeyname, columnSet, headerTr$) {
if (typeof ListElement === 'object') {
if (parentKeyname != '')
parentKeyname = parentKeyname + '-';
for (var key in ListElement) {
var keyname = parentKeyname + key;
recursiveHeaderCheck(ListElement[key], selector, keyname, columnSet, headerTr$);
}
} else {
if ($.inArray(parentKeyname, columnSet) == -1) {
columnSet.push(parentKeyname);
headerTr$.append($('<th/>').html(parentKeyname));
}
}
}
function getCellValue(nestedStructure, columnHeader) {
var subElement = nestedStructure;
var subHeaders = columnHeader.split("-");
for (var k = 0; k < subHeaders.length; k++) {
if (typeof subElement === 'object' && subElement != null)
subElement = subElement[subHeaders[k]];
}
return subElement;
}
I am currently trying to learn about backtracking Algorithms and have been working on a Sudoku game. I understand the basic working of the algorithm and have written a Sudoku solver using it.
My current problem is related to removing a set amount of numbers from a completed Sudoku grid to create a valid Sudoku with a unique solution.
I have checked similar questions on here but have found no answers.
Here is an example of a solved Sudoku grid:
solvedSudokuGrid =
[["8","6","1","3","4","2","9","5","7"],
["2","5","3","8","7","9","4","6","1"],
["4","9","7","6","5","1","2","3","8"],
["6","7","2","5","1","8","3","9","4"],
["9","1","4","7","2","3","6","8","5"],
["5","3","8","4","9","6","7","1","2"],
["3","4","6","2","8","5","1","7","9"],
["7","8","9","1","3","4","5","2","6"],
["1","2","5","9","6","7","8","4","3"]];
Here is the function to remove a set amount of numbers from the grid:
function removeNrs(grid, nrsToBeRemoved) {
//check if enough numbers have been removed
if (nrsToBeRemoved <= 0) {
return true;
}
//find the next random full cell and set the grid to "" on that cell to remove a number
var nextNr = shuffle(findFullCells(grid))[0];
var row = nextNr[0];
var column = nextNr[1];
var value = grid[row][column];
grid[row][column] = "";
nrsToBeRemoved--;
//check if the sudoku grid has only 1 solution if yes start recursion
if (countAllSolutions(grid) < 2){
if(removeNrs(grid, nrsToBeRemoved)){
return grid;
}
}
//if the sudoku grid has more than 1 possible solution return the grid to the previous state and backtrack
grid[row][column] = value;
return false;
}
Here is the problem: If I enter a low amount of numbers to be removed the function works.
ex:
removeNrs(solvedSudokuGrid, 5); //returns a valid grid
If I enter a higher amount of numbers to be removed the function simply returns false.
ex:
removeNrs(solvedSudokuGrid, 50); //returns false
From the basic debugging that I have tried I can see that the function works as long as it does not have to backtrack. If the function has to backtrack it seems to return all the way to the beginning and finish with the original grid before returning false.
Any help, explenations or things to read are much appreciated.
Edit:
https://jsfiddle.net/mg57u0mv/
Here is the complete code but some of the names of functions and variables have been changed to fit better with the whole code.
function createTable() {
var tbl = document.createElement("table");
var tbdy = document.createElement("tbody");
for (var row = 0; row < 9; row++) {
var tr = document.createElement("tr");
for (var column = 0; column < 9; column++) {
var td = document.createElement("td");
var input = document.createElement("input");
input.type = "text";
input.id = "r"+row+"c"+column;
input.className = "grid-inputs grid-inputs-row-" + row;
//input.placeholder = "[" + row + " , " + column + "]";
//input.placeholder = input.id;
if ((row+1) % 3 === 0) {
td.style.borderBottom = "3px solid black";
}
if ((column+1) % 3 === 0) {
td.style.borderRight = "3px solid black";
}
tr.appendChild(td);
td.appendChild(input);
}
tbdy.appendChild(tr);
}
tbl.appendChild(tbdy);
document.body.appendChild(tbl);
}
function createButton(text, func) {
var button = document.createElement("button");
var t = document.createTextNode(text);
button.onclick = func;
button.appendChild(t);
document.body.appendChild(button);
}
function shuffle(array) {
var counter = array.length;
var temp, index;
while (counter) {
index = Math.floor(Math.random() * counter);
counter--;
temp = array[counter];
array[counter] = array[index];
array[index] = temp;
}
return array;
}
function retrieveGrid() {
var result = [];
var rowContents = [];
for (var row = 0; row < 9; row++) {
for (var column = 0; column < 9; column++) {
rowContents.push(document.getElementsByClassName("grid-inputs-row-"+row)[column].value);
}
result.push(rowContents);
rowContents = [];
}
return result;
}
function printGrid(grid) {
for (var row = 0; row < 9; row++) {
for (var column = 0; column < 9; column++) {
document.getElementsByClassName("grid-inputs-row-"+row)[column].value = grid[row][column];
}
}
}
function checkRowColumnBlock(grid, row, column, value) {
//create row, column and block lists to be checked for doubles
var rowList = grid[row];
var columnList = [];
for (var columnCounter = 0; columnCounter < 9; columnCounter++) {
columnList.push(grid[columnCounter][column]);
}
var blockList = [];
for (var startRow = Math.floor(row/3) * 3, endRow = startRow + 3; startRow < endRow; startRow++) {
for (var startColumn = Math.floor(column/3) * 3, endColumn = startColumn + 3; startColumn < endColumn; startColumn++) {
blockList.push(grid[startRow][startColumn]);
}
}
//check row, column and block list for value
if (rowList.indexOf(value.toString()) === -1 &&
columnList.indexOf(value.toString()) === -1 &&
blockList.indexOf(value.toString()) === -1) {
return true;
} else {
return false;
}
}
function checkGrid(grid) {
for (var row = 0; row < 9; row++) {
for (var column = 0; column < 9; column++) {
if (grid[row][column] !== "") {
var value = grid[row][column];
grid[row][column] = "";
if (!checkRowColumnBlock(grid, row, column, value)) {
console.log("Invalid Grid");
return false;
}
grid[row][column] = value;
}
}
}
console.log("Valid Grid");
return true;
}
function findEmptyCells(grid) {
var result = [];
for (var row = 0; row < 9; row++){
for (var column = 0; column < 9; column++) {
if (grid[row][column] === "") {
result.push([row , column]);
}
}
}
if (result.length == 0) {
result = false;
}
return result;
}
function sortPossibilties(grid) {
var result = [];
var listOfEmptyCells = findEmptyCells(grid);
if (listOfEmptyCells === false) {
return false;
}
var listOfPossibilities = findPossibilitiesForGrid(grid);
var counter = listOfEmptyCells.length;
for (var cell = 0; cell < counter; cell++) {
result.push({"cell": listOfEmptyCells[cell], "possibilities": listOfPossibilities[cell]});
}
result.sort(function (first, second) {
return first.possibilities.length - second.possibilities.length;
});
return result;
}
function findNextEmptyCell(grid) {
var sortedEmptyCells = sortPossibilties(grid);
if (sortedEmptyCells === false) {
return false;
}
return sortedEmptyCells[0];
}
function findFullCells(grid) {
var result = [];
for (var row = 0; row < 9; row++){
for (var column = 0; column < 9; column++) {
if (grid[row][column] !== "") {
result.push([row , column]);
}
}
}
if (result.length == 0) {
result = false;
}
return result;
}
function findRandomFullCell(listOfFullCells) {
if (listOfFullCells === false) {
return false;
}
var result = listOfFullCells[Math.floor(Math.random() * listOfFullCells.length)];
return result;
}
function createEmptyGrid() {
//create grid 9x9 fill with blankspace
var grid = [];
for (var gridCounter = 0; gridCounter < 9; gridCounter++) {
grid.push(new Array(9).fill(""));
}
return grid;
}
function createIncRandomGrid(numberOfRandomCells) {
var grid = createEmptyGrid();
for (var counter = 0; counter < numberOfRandomCells; counter++) {
grid[Math.floor(Math.random() * 9)][Math.floor(Math.random() * 9)] =
Math.floor(Math.random() * 9 + 1).toString();
}
return grid;
}
function createCorRandomGrid(numberOfRandomCells) {
var grid;
do {grid = createIncRandomGrid(numberOfRandomCells);}
while (checkGrid(grid) === false);
return grid;
}
function findPossibilitiesForCell(grid, row, column) {
var possibilities = [];
for (var value = 1; value < 10; value++) {
if (checkRowColumnBlock(grid, row, column, value)) {
possibilities.push(value.toString());
}
}
return possibilities;
}
function findPossibilitiesForGrid(grid) {
var result = [];
var listOfEmptyCells = findEmptyCells(grid);
var amountOfEmptyCells = listOfEmptyCells.length;
for (var cell = 0; cell < amountOfEmptyCells; cell++) {
var row = listOfEmptyCells[cell][0];
var column = listOfEmptyCells[cell][1];
result.push(findPossibilitiesForCell(grid, row, column));
}
return result;
}
function solveSudoku(grid) {
var emptyCell = findNextEmptyCell(grid);
if (emptyCell === false) {
return true;
}
var row = emptyCell.cell[0];
var column = emptyCell.cell[1];
var valueList = shuffle(emptyCell.possibilities);
var valueListLength = valueList.length;
for (var valueIndex = 0; valueIndex < valueListLength; valueIndex++) {
if (checkRowColumnBlock(grid, row, column, valueList[valueIndex])) {
grid[row][column] = valueList[valueIndex].toString();
if (solveSudoku(grid)) {
return grid;
}
grid[row][column] = "";
}
}
return false;
}
function countAllSolutions(grid) {
var nrOfSolutions = 1;
function solveAll(grid) {
var emptyCell = findNextEmptyCell(grid);
if (emptyCell === false || nrOfSolutions > 1) {
return true;
}
var row = emptyCell.cell[0];
var column = emptyCell.cell[1];
var valueList = shuffle(emptyCell.possibilities);
var valueListLength = valueList.length;
for (var valueIndex = 0; valueIndex < valueListLength; valueIndex++) {
if (checkRowColumnBlock(grid, row, column, valueList[valueIndex])) {
grid[row][column] = valueList[valueIndex].toString();
if (solveAll(grid)) {
nrOfSolutions++;
}
grid[row][column] = "";
}
}
return false;
}
solveAll(grid);
return nrOfSolutions-1;
}
function findPossibilitiesForFullCell(grid, row, column) {
var possibilities = [];
var originalValue = grid[row][column];
grid[row][column] = "";
for (var value = 1; value < 10; value++) {
if (checkRowColumnBlock(grid, row, column, value)) {
possibilities.push(value.toString());
}
}
grid[row][column] = originalValue;
return possibilities;
}
function findPossibilitiesForFullGrid(grid) {
var result = [];
var listOfFullCells = findFullCells(grid);
var amountOfFullCells = listOfFullCells.length;
for (var cell = 0; cell < amountOfFullCells; cell++) {
var row = listOfFullCells[cell][0];
var column = listOfFullCells[cell][1];
result.push(findPossibilitiesForFullCell(grid, row, column));
}
return result;
}
function sortFullCells(grid) {
var result = [];
var listOfFullCells = findFullCells(grid);
if (listOfFullCells === false) {
return false;
}
var listOfPossibilities = findPossibilitiesForFullGrid(grid);
var counter = listOfFullCells.length;
for (var cell = 0; cell < counter; cell++) {
result.push({"cell": listOfFullCells[cell], "possibilities": listOfPossibilities[cell]});
}
result.sort(function (first, second) {
return first.possibilities.length - second.possibilities.length;
});
return result;
}
function findNextFullCells(grid) {
var sortedFullCells = sortFullCells(grid);
if (sortedFullCells === false) {
return false;
}
var result = [];
result.push(sortedFullCells[0]);
for (var cell = 1, length = sortedFullCells.length; cell < length; cell++){
if(sortedFullCells[cell].possibilities.length === sortedFullCells[0].possibilities.length) {
result.push(sortedFullCells[cell]);
}
}
return result;
}
function removeCells(grid, cellsToBeRemoved) {
if (cellsToBeRemoved <= 0) {
return grid;
}
var nextCell = shuffle(findFullCells(grid))[0];
var row = nextCell[0];
var column = nextCell[1];
var value = grid[row][column];
grid[row][column] = "";
cellsToBeRemoved--;
if (countAllSolutions(grid) < 2) {
grid = removeCells(grid, cellsToBeRemoved);
return grid;
} else {
grid[row][column] = value;
grid = removeCells(grid, cellsToBeRemoved);
}
return grid;
}
createTable();
createButton("Solve Sudoku", function () {
console.time("Solved");
printGrid(solveSudoku(retrieveGrid()));
console.timeEnd("Solved");
});
createButton("Remove Cells", function () {
console.time("Removed");
printGrid(removeCells(retrieveGrid(),55));
console.timeEnd("Removed");
});
createButton("Count Solutions", function () {
console.time("Counting");
console.log(countAllSolutions(retrieveGrid()));
console.timeEnd("Counting");
});
createButton("Create Random Grid", function () {
printGrid(createIncRandomGrid(100));
});
createButton("Create Correct Random Grid", function () {
printGrid(createCorRandomGrid(17));
});
createButton("Check Grid", function () {
checkGrid(retrieveGrid());
});
createButton("Count Full Cells", function () {
console.log(findFullCells(retrieveGrid()).length);
});
createButton("Count Empty Cells", function () {
console.log(findEmptyCells(retrieveGrid()).length);
});
createButton("Sort Empty Cells", function () {
console.log(sortPossibilties(retrieveGrid()));
});
createButton("Sort Full Cells", function () {
console.log(sortFullCells(retrieveGrid()));
});
createButton("Reset Grid", function () {
printGrid(createEmptyGrid());
});
I haven't actually tested it but I did test a similar function.
Try this at the end, replacing your last eight lines:
if (countAllSolutions(grid) < 2) grid = removeNrs(grid, nrsToBeRemoved);
else grid[row][column] = value;
return grid;
function selectTo(cell) {
var row = cell.parent();
var cellIndex = cell.index();
var rowIndex = row.index();
var rowStart, rowEnd, cellStart, cellEnd;
if (rowIndex < startRowIndex) {
rowStart = rowIndex;
rowEnd = startRowIndex;
sessionStorage.setItem('rowStart', rowStart);
sessionStorage.setItem('rowEnd', rowEnd);
} else {
rowStart = startRowIndex;
rowEnd = rowIndex;
sessionStorage.setItem('rowStart', rowStart);
sessionStorage.setItem('rowEnd', rowEnd);
}
if (cellIndex < startCellIndex) {
cellStart = cellIndex;
cellEnd = startCellIndex;
sessionStorage.setItem('cellStart', cellStart);
sessionStorage.setItem('cellEnd', cellEnd);
} else {
cellStart = startCellIndex;
cellEnd = cellIndex;
sessionStorage.setItem('cellStart', cellStart);
sessionStorage.setItem('cellEnd', cellEnd);
}
for (var i = rowStart; i <= rowEnd; i++) {
var TableID = sessionStorage.getItem("TableID");
var table6 = document.getElementById(TableID);
var row6 = table6.getElementsByTagName('tr')[i];
var rowCells = row6.getElementsByTagName('td');
for (var j = cellStart; j <= cellEnd; j++) {
rowCells[j].className = "hover";
}
}
}
var TableID = sessionStorage.getItem("TableID");
var cellStart = sessionStorage.getItem("cellStart");
var cellEnd = sessionStorage.getItem("cellEnd");
var rowStart = sessionStorage.getItem("rowStart");
var rowEnd = sessionStorage.getItem("rowEnd");
for (var i = rowStart; i <= rowEnd; i++) {
var myTable = document.getElementById(TableID);
var row10 = myTable.getElementsByTagName('tr')[i];
var rowCells = row10.getElementsByTagName('td');
for (var j = cellStart; j < cellEnd; j++) {
if (j === cellStart && i === rowStart)
continue;
//rowCells[j].style.display = "none";
myTable.rows[i].deleteCell(j);
}
}
When I delete cells, use a different method table.row[i].deleteCell(j); or removechild I get out of range error.
mesage:
Uncaught DOMException: Failed to execute 'deleteCell' on
'HTMLTableRowElement': The value provided (3) is outside the range [0,
3).
at init.callback
I find solution:
var listHover = document.querySelectorAll('.hover');
for (var i = 0; i < listHover.length; i++) {
if (i > 0) {
listHover[i].style.display = 'none';
}
}
I want to add a new row in between rows. Currently new row can be added only after last row.
reference: http://getcontenttools.com/
Current JS code
row = new ContentEdit.TableRow();
_ref = cell.parent().children;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
child = _ref[_i];
newCell = new ContentEdit.TableCell(child.tagName(), child._attributes);
newCellText = new ContentEdit.TableCellText('');
newCell.attach(newCellText);
row.attach(newCell);
}
section = this.closest(function (node) {
return node.type() === 'TableRow';
});
section.attach(row);
Below code snippet worked for me.
TableCellText.prototype._isLastCell = function () {
var cell, row, section, table;
debugger;
cell = this.parent();
row = cell.parent();
section = row.parent();
table = section.parent();
if (cell !== row.children[row.children.length - 1]) {
return false;
}
return cell === row.children[row.children.length - 1];
};
TableCellText.prototype._keyTab = function(ev) {
var cell, child, grandParent, newCell, newCellText, row, section, _i, _len, _ref;
ev.preventDefault();
cell = this.parent();
if (ev.shiftKey) {
if (this._isInFirstRow() && cell.parent().children[0] === cell) {
return;
}
return this.previousContent().focus();
} else {
if (!this.can('spawn')) {
return;
}
grandParent = cell.parent().parent();
if (grandParent.tagName() === 'tbody' && this._isLastInSection()) {
row = new ContentEdit.TableRow();
_ref = cell.parent().children;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
child = _ref[_i];
newCell = new ContentEdit.TableCell(child.tagName(), child._attributes);
newCellText = new ContentEdit.TableCellText('');
newCell.attach(newCellText);
row.attach(newCell);
}
section = this.closest(function(node) {
return node.type() === 'TableSection';
});
section.attach(row);
return row.children[0].tableCellText().focus();
}
else if (grandParent.tagName() === 'tbody' && this._isLastCell()) {
row = new ContentEdit.TableRow();
_ref = cell.parent().children;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
child = _ref[_i];
newCell = new ContentEdit.TableCell(child.tagName(), child._attributes);
newCellText = new ContentEdit.TableCellText('');
newCell.attach(newCellText);
row.attach(newCell);
}
section = this.closest(function (node) {
return node.type() === 'TableRow';
});
section.parent().attach(row, grandParent.children.indexOf(section));
return row.children[0].tableCellText().focus();
}
else {
return this.nextContent().focus();
}
}
};
New row above the current row with shift + enter:
TableCellText.prototype._keyReturn = function(ev) {
ev.preventDefault();
if (ev.shiftKey) {
var cell, child, grandParent, newCell, newCellText, row, section, _i, _len, _ref;
cell = this.parent();
if (!this.can('spawn')) {
return;
}
grandParent = cell.parent().parent();
if (grandParent.tagName() === 'tbody') {
row = new ContentEdit.TableRow();
_ref = cell.parent().children;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
child = _ref[_i];
newCell = new ContentEdit.TableCell(child.tagName(), child._attributes);
newCellText = new ContentEdit.TableCellText('');
newCell.attach(newCellText);
row.attach(newCell);
}
section = this.closest(function (node) {
return node.type() === 'TableRow';
});
section.parent().attach(row, grandParent.children.indexOf(section));
return row.children[0].tableCellText().focus();
} else {
return this.nextContent().focus();
}
} else
return this._keyTab({
'shiftKey': false,
'preventDefault': function() {}
});
};
I have a table in my popup and I save the values entered by a user to localStorage. Here are the snippets.
popup.html
<table id="main_table">
</table>
<script src="popup.js"></script>
popup.js
function create_row() {
localStorage["last_session"] = true;
var table = document.getElementById("main_table");
var n = table.rows.length;
var m = table.rows[0].cells.length;
var row = table.insertRow(n);
if (!localStorage['use_storage']) {
if (n === 1) {
localStorage["cells"] = JSON.stringify([{}]);
}
else if (n > 1) {
var cells = JSON.parse(localStorage["cells"]);
cells.push({});
localStorage["cells"] = JSON.stringify(cells);
}
}
var cell = row.insertCell(0);
cell.innerHTML = n;
for (j=1; j<m; j++) {
create_cell(n-1, j, row);
}
return row
}
function create_cell(i, j, row){
var cell = row.insertCell(j);
if (j == 1) {
cell.innerHTML = "<input size=10>";
}
else {
cell.innerHTML = "<input size=4>";
}
cell.addEventListener("change", function () {
var cells = JSON.parse(localStorage["cells"]);
cells[i.toString()][j.toString()] = cell.childNodes[0].value;
localStorage["cells"] = JSON.stringify(cells);
})
}
document.getElementById('create_row').onclick = create_row;
// restore a table
if (localStorage["last_session"]) {
localStorage["use_storage"] = true;
try {
var cells = JSON.parse(localStorage["cells"]);
var n = cells.length;
var table = document.getElementById("main_table")
for (i=0; i<n; i++) {
var row = create_row(true);
var cell = cells[i]
for (var key in cell) {
if (cell.hasOwnProperty(key)) {
var col = parseInt(key);
var val = cell[key];
row.cells[col].childNodes[0].value = val;
}
}
}
} catch (e) {
console.log("Catched error");
console.log(e);
}
if (localStorage["results"]) {
show_results();
}
localStorage['use_storage'] = false;
}
In my browser it works as it is supposed, that is after refreshing a page popup.html I have the state where I left (number of rows and values are preserved). However, in my chrome extension, after clicking to any area and thus reloading the extension, I have the initial empty table.
How can I preserve the table in this particular case?