I have the following code run to get the values from dynamically created table elements. I can't get the input data when I submit the display (see console). I am unsure what to do, please advise!
console.clear();
var dimensions = [4, 4];
var controlType = [];
// empty and repopulate display with specified dimensions
function populate() {
var table = $("#display > table > tbody");
var tr = document.createElement("tr");
var td = document.createElement("td");
table.empty();
let row = 0;
for (let i = 0; i < dimensions[1]; i++) {
row++;
let column = 0;
var newRow = $(tr).clone().appendTo(table);
for (let i = 0; i < dimensions[0]; i++) {
column++
let position = row + "-" + column
let newCell = $(td).clone().appendTo(newRow);
$(newCell).append("<input type='button' name='" + position + "' class='on' form='display'>")
$(newCell.children()).click(function () {
let inputType = $("input:checked").val();
if (inputType == "lights" && !$(this).hasClass("wall")) {
$(this).toggleClass("on off");
} else if (inputType == "walls") {
$(this).toggleClass("wall");
};
});
};
};
console.log("Populated display\nDimensions:", dimensions[0] + "x" + dimensions[1]);
};
// when document is ready
$(document).ready(function () {
populate();
// solve the puzzle input
$("#display").submit(function (e) {
e.preventDefault();
let formData = $(this).serializeArray();
console.log(formData);
});
// generate a dimensions list containing user input height and width on submit
$("#options").submit(function (e) {
e.preventDefault();
let formData = $(this).serializeArray();
formData.forEach(function (i) {
let val = Math.round(i.value)
if (i.name == "width") dimensions[0] = val;
if (i.name == "height") dimensions[1] = val;
});
populate();
});
});
:root {
--font: Arial;
--fs: 30px;
--inputBg: whitesmoke;
--border: 2px solid lightgrey;
}
/* always show arrow buttons on number input */
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
opacity: 1;
}
/* body formatting */
body {
width: auto;
height: auto;
font-family: var(--font);
font-size: var(--fs)
}
/* lights out puzzle formatting */
#lightsOut {
width: fit-content;
height: auto;
margin: 0px;
border: var(--border);
display: flex;
gap: 0.2em;
}
/* display formatting */
#display {
& table {
height: fit-content;
margin-top: 0.1em;
margin-right: 0.1em;
border-collapse: collapse;
& tr {
& td {
padding: 0px;
& input {
width: 1.5em;
height: 1.5em;
font-size: inherit;
margin-bottom: 0.1em;
margin-left: 0.1em;
padding: 0px;
}
& .on {
background-color: var(--inputBg);
border: var(--border);
}
& .off {
background-color: darkgrey;
border: 2px solid grey;
}
& .wall {
background-color: transparent;
border: 2px solid transparent;
}
}
}
}
& span {
width: 100%-var(--margin);
height: 1.5em;
display: flex;
font-size: inherit;
text-align: center;
margin-bottom: 0.1em;
margin-left: 0.1em;
& input[type="submit"] {
width: 100%;
height: 1.5em;
font-size: inherit;
background-color: var(--inputBg);
margin-right: 0.1em;
border: var(--border);
}
}
}
/* user interface */
#ui {
display: flex;
flex-direction: column;
margin-top: 0.1em;
margin-right: 0.1em;
/* options formatting */
& #options,
#controls {
display: flex;
flex-direction: column;
& span {
width: 100%;
height: 1.5em;
display: flex;
justify-content: left;
font-size: inherit;
text-align: center;
margin-bottom: 0.1em;
margin-left: 0.1em;
& label {
width: 3.25em;
height: 1.5em;
font-size: inherit;
margin-right: 0.5em;
display: flex;
align-items: center;
}
& input[type="number"] {
width: 1.5em;
height: 1em;
font-size: inherit;
padding: 0px;
align-self: center;
}
& input[type="radio"] {
width: 1em;
height: 1em;
font-size: inherit;
margin-left: 0px;
align-self: center;
}
& input[type="submit"] {
width: 100%;
height: 1.5em;
font-size: inherit;
background-color: var(--inputBg);
margin-right: 0.1em;
border: var(--border);
}
}
}
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="lightsOut.css">
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="lightsOut.js"></script>
</head>
<body>
<div id="lightsOut">
<form id="display">
<table>
<tbody>
</tbody>
</table>
<span class="submit">
<input value="Solve" type="submit">
</span>
</form>
<span id="ui">
<form id="options">
<span class="number">
<label for="width">Width:</label>
<input name="width" id="width" type="number" value="4" min="3" max="15">
</span>
<span class="number">
<label for="height">Height:</label>
<input name="height" id="height" type="number" value="4" min="3" max="15">
</span>
<span class="submit">
<input value="Apply" type="submit">
</span>
</form>
<form id="controls">
<span class="radio">
<input name="type" id="lights" type="radio" value="lights" checked>
<label for="lights">Lights</label>
</span>
<span class="radio">
<input name="type" id="walls" type="radio" value="walls">
<label for="walls">Walls</label>
</span>
</form>
</span>
</div>
</body>
</html>
When you hit the Solve button, the console has an empty list instead of all the inputs. I tried adding a value to each input but that didn't help.
Here is a solution....
It consists of parsing all the cells of the table to get the different values of className
and put them in an array.
Sorry, I lost a little time to restore your interface...
const
formOptionsControls = document.querySelector('#options-controls')
, lightsOut_Table = document.querySelector('#lightsOut > table > tbody')
, lightsOut_Solve = document.querySelector('#lightsOut > table > caption')
;
setTableDims();
formOptionsControls.addEventListener('submit',setTableDims);
lightsOut_Table.addEventListener('click',({target: TDx}) =>
{
if (!TDx.matches('td')) return;
let xClassName = formOptionsControls.type.value === 'wall' ? 'wall' : 'off';
TDx.classList.toggle(xClassName);
// console.log( TDx.closest('tr').rowIndex, TDx.cellIndex );
})
lightsOut_Solve.addEventListener('click', e =>
{
// if (!formOptionsControls.checkValidity() ) return;
let
xRows = lightsOut_Table.rows.length
, xCols = lightsOut_Table.rows[0].cells.length
, resp = []
;
for( let r = 0; r < xRows; r++)
{
resp.push([]);
for( let c = 0; c < xCols; c++)
resp[r].push( lightsOut_Table.rows[r].cells[c].className || 'on');
}
console.clear();
console.log( JSON.stringify({xRows,xCols}) );
console.log( JSON.stringify(resp,0,2) );
})
function setTableDims(e)
{
if (!!e) e.preventDefault();
let dimensions = [ formOptionsControls.width.valueAsNumber, formOptionsControls.height.valueAsNumber ];
console.clear();
console.log("Populated display\nDimensions:", dimensions[0] + "x" + dimensions[1]);
while (lightsOut_Table.rows.length ) lightsOut_Table.deleteRow(-1);
for (let r=0;r<formOptionsControls.height.valueAsNumber; r++)
{
let newRow = lightsOut_Table.insertRow();
for(let c = formOptionsControls.width.valueAsNumber; c--;) newRow.insertCell();
}
}
body {
font-family : Arial, Helvetica, sans-serif;
font-size : 30px;
}
#lightsOut {
border : 0.1em solid lightgrey;
display : flex;
gap : 0.2em;
width : fit-content;
line-height : 1.5em;
}
table {
border-collapse : separate;
border-spacing : 0.1em;
background : white;
height : fit-content;
}
td, caption {
cursor : pointer;
height : 1.5em;
background : whitesmoke;
box-sizing : border-box;
border : 0.1em solid lightgrey;
}
td {
width : 1.5em;
}
td.off {
background : darkgrey;
border-color : grey;
}
td.wall {
background : white !important;
border-color : white !important;
}
caption {
caption-side : bottom;
margin : 0 .1em .1em .1em;
}
form#options-controls {
width : 6em;
padding : .2em .2em 0 0;
}
label {
display : block;
}
label > input[type="number"] {
font-size : .9em;
text-align : center;
float : inline-end;
padding : 0;
width : 2.3em;
}
button {
display : block;
width : 6em;
font-size : 1em;
padding : 0;
height : 1.5em;
background : whitesmoke;
box-sizing : border-box;
border : 0.1em solid lightgrey;
margin : .1em 0 .3em 0;
cursor : pointer;
}
input[type="radio"] {
width : 1em;
height : 1em;
font-size : inherit;
margin-left : .2em;
align-self : center;
}
label:has(input[type="radio"]) {
cursor : pointer;
}
td:hover, caption:hover, button:hover {
background : #b5d11566;
}
<div id="lightsOut">
<table>
<caption> Solve </caption>
<tbody></tbody>
</table>
<form id="options-controls">
<label>
Width:
<input name="width" type="number" value="4" min="3" max="15" required>
</label>
<label>
Height:
<input name="height" type="number" value="4" min="3" max="15" required>
</label>
<button> Apply </button>
<label>
<input name="type" type="radio" value="light" checked >
Lights
</label>
<label>
<input name="type" type="radio" value="wall" >
walls
</label>
</form>
</div>