2

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.

9
  • 1
    there is no input values in your form #display, so the .serializeArray() will always return an empty array. Commented Sep 23, 2024 at 17:40
  • I tried adding input values but it still does the same thing. Commented Sep 23, 2024 at 17:42
  • 3
    Buttons aren't included when you serialize a form. Use checkboxes, the array will contain the checked ones. Commented Sep 23, 2024 at 17:42
  • 1
    What kind of answer did you expect from your form #display ? Commented Sep 23, 2024 at 17:45
  • Show where/how you added an input to #display; I added a very simple text input and it serialized as expected. Commented Sep 23, 2024 at 17:48

1 Answer 1

1

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>

Sign up to request clarification or add additional context in comments.

4 Comments

This seems like it will work. I'll check it out.
Looking over this whole thing is providing me with more input than I could've asked for, so thank you for spending your time reformatting. Is there any problem using nested & element in CSS? I find it easier to read and write, or is it a personal preference-type thing? Also not me rewriting everything based on yours loool
This is beautiful. I've been staring at it for 15 minutes now.
@TheDudeofDC No, there is no problem with nesting styles in CSS, I have not yet acquired the full dexterity to work with it. It's just a matter of time. Otherwise thank you, your messages warm my heart.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.