skip to Main Content

I am currently creating a random group generator. The first part of this project requires me to make a table. This table can take in two inputs per row, a first name and a last name.

What needs to happen is that after a first and last name is inputted into a row, a new row should be created just below it. When a row is filled out, two IDs should be made: firstNamerowNumber and lastNamerowNumber. This is because I would like this table to be able to extend onward until my Chromebook breaks.

Problem: However, not just 1 row is being made at a time. Let’s say you have 1 row filled out, 1 new row is added (that’s good). Now say you have 2 rows filled out, 2 new rows are added (bad).

Question: How can I make it so that only 1 row is added at all times after a change event?

Note: For clarity, each first and last name need unique IDs because they will be stored in arrays and then used to create random groups later, making it important that the correct first name goes with the correct last name.

const inputArticle = document.querySelector('#input-article');
const outputArticle = document.querySelector('#output-article');
const table = document.querySelector('#table');
const addRowButton = document.querySelector('#addRow');
const submitButton = document.querySelector('#submit');

let names = [];
let rowNumber = 0; //Maybe I could try to use a for loop? I couldn't get that to work, though

function addRow() {
    let row = table.insertRow(-1);
    let cell1 = row.insertCell(0);
    let cell2 = row.insertCell(1);
    let firstNameInput = document.createElement("input");
    let lastNameInput = document.createElement("input");

    firstNameInput.type = "text";
    firstNameInput.setAttribute('id', `firstName${rowNumber}`);
    cell1.appendChild(firstNameInput);
        
    lastNameInput.type = "text";
    lastNameInput.setAttribute('id', `lastName${rowNumber}`);
    cell2.appendChild(lastNameInput);

    table.addEventListener('change', () => {
        if (firstNameInput == null || lastNameInput == null) {
            return null;
        } else if (firstNameInput.value && lastNameInput.value) {
            addRow();
            rowNumber++;
            let firstName = firstNameInput.value;
            let lastName = lastNameInput.value;
        }
    })   
}

function submit() {
    let confirmation = confirm("Are you sure you have all of the names?");

    if (confirmation) {
        inputArticle.classList.add("hidden");
        outputArticle.classList.remove("hidden");
    }
}

addRowButton.addEventListener('click', () => {
    addRow();
    addRowButton.disabled = true;
})

inputArticle.classList.remove("hidden");
outputArticle.classList.add("hidden");
submitButton.addEventListener('click', submit);
#input-article.hidden {
    display: none;
}

table {
    text-align: center;
    align-items: center;
}

th {
    width: 50vmin;
    height: 10vmin;
    font-size: 20pt;
    font-weight: 800;
}

input {
    width: 50vmin;
    height: 5vmin;
    text-align: center;
    align-items: center;
    font-size: 18pt;
    font-weight: 400;
    font-family: Georgia, 'Times New Roman', Times, serif;
    border: 0;
    padding: 0;
}

#buttons {
    width: 100vmin;
    height: 10vmin;
}

#submit {
    background-color: blue;
    color: white;
    border: 0;
    position: relative;
    left: 84%;
}

#output-article.hidden {
    display: none;
}
<!DOCTYPE html>
<html lang="en">

<html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE-edge">
        <meta name="viewport", content="width=device-width, initial-scale=1.0">
        <meta name="author" content="Christian Davis">
        <link rel="stylesheet" href="styles.css">
        <title>Random Group Generator</title>
    </head>

    <body>
        <article id="input-article">
            <table id="table" border="1">
                <tr>
                    <th>First Name:</th>
                    <th>Last Name:</th>
                </tr>
            </table> <br>

            <div id="buttons">
                <button id="addRow">Add Row</button>
                <button id="submit">Submit</button>
            </div>
        </article>

        <article id="output-article">
            Output
        </article>

        <script src="try.js"></script>
    </body>
</html>

3

Answers


  1. It’s the way you’re checking if you should add a new row that is braking your logic.

    I’d tackle this like so:

    function addRow() {
        // unchanged code
    
        firstNameInput.addEventListener('change', onRowChange);
        lastNameInput.addEventListener('change', onRowChange);
    }
    
    function onRowChange(e) {
      if ([ ...e.target.parentNode.parentNode.children ].every(c => c.children[0].value)) {
          rowNumber++;
          addRow();
      }
    }
    

    So we add 2 eventlisteners to both the inputs, then we call onRowChange where we

    1. Get the second parent of the input (the table row)

    2. Loop through the children, so we check both first and last name (and maybe more later)

    3. If both of them have a truely value

      1. Bump rowCounter (could be replaced with a checker)
      2. Call addRow()

    Updated Demo:

    const inputArticle = document.querySelector('#input-article');
    const outputArticle = document.querySelector('#output-article');
    const table = document.querySelector('#table');
    const addRowButton = document.querySelector('#addRow');
    const submitButton = document.querySelector('#submit');
    
    let names = [];
    let rowNumber = 0; //Maybe I could try to use a for loop? I couldn't get that to work, though
    
    function addRow() {
        let row = table.insertRow(-1);
        let cell1 = row.insertCell(0);
        let cell2 = row.insertCell(1);
        let firstNameInput = document.createElement("input");
        let lastNameInput = document.createElement("input");
    
        firstNameInput.type = "text";
        firstNameInput.setAttribute('id', `firstName${rowNumber}`);
        cell1.appendChild(firstNameInput);
            
        lastNameInput.type = "text";
        lastNameInput.setAttribute('id', `lastName${rowNumber}`);
        cell2.appendChild(lastNameInput);
    
        firstNameInput.addEventListener('change', onRowChange);
        lastNameInput.addEventListener('change', onRowChange);
    }
    
    function onRowChange(e) {
      if ([ ...e.target.parentNode.parentNode.children ].every(c => c.children[0].value)) {
          rowNumber++;
          addRow();
      }
    }
    
    function submit() {
        let confirmation = confirm("Are you sure you have all of the names?");
    
        if (confirmation) {
            inputArticle.classList.add("hidden");
            outputArticle.classList.remove("hidden");
        }
    }
    
    addRowButton.addEventListener('click', () => {
        addRow();
        addRowButton.disabled = true;
    })
    
    inputArticle.classList.remove("hidden");
    outputArticle.classList.add("hidden");
    submitButton.addEventListener('click', submit);
    #input-article.hidden {
        display: none;
    }
    
    table {
        text-align: center;
        align-items: center;
    }
    
    th {
        width: 50vmin;
        height: 10vmin;
        font-size: 20pt;
        font-weight: 800;
    }
    
    input {
        width: 50vmin;
        height: 5vmin;
        text-align: center;
        align-items: center;
        font-size: 18pt;
        font-weight: 400;
        font-family: Georgia, 'Times New Roman', Times, serif;
        border: 0;
        padding: 0;
    }
    
    #buttons {
        width: 100vmin;
        height: 10vmin;
    }
    
    #submit {
        background-color: blue;
        color: white;
        border: 0;
        position: relative;
        left: 84%;
    }
    
    #output-article.hidden {
        display: none;
    }
    <!DOCTYPE html>
    <html lang="en">
    
    <html>
        <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE-edge">
            <meta name="viewport", content="width=device-width, initial-scale=1.0">
            <meta name="author" content="Christian Davis">
            <link rel="stylesheet" href="styles.css">
            <title>Random Group Generator</title>
        </head>
    
        <body>
            <article id="input-article">
                <table id="table" border="1">
                    <tr>
                        <th>First Name:</th>
                        <th>Last Name:</th>
                    </tr>
                </table> <br>
    
                <div id="buttons">
                    <button id="addRow">Add Row</button>
                    <button id="submit">Submit</button>
                </div>
            </article>
    
            <article id="output-article">
                Output
            </article>
    
            <script src="try.js"></script>
        </body>
    </html>
    Login or Signup to reply.
  2. Instead of adding more and more event listeners to the table element, just add a change event listener to both inputs in the newly-created row.

    function handleChange() {
        // this is the original code in the event handler
        if (firstNameInput == null || lastNameInput == null) {
            return null;
        } else if (firstNameInput.value && lastNameInput.value) {
            addRow();
            rowNumber++;
            let firstName = firstNameInput.value;
            let lastName = lastNameInput.value;
        }
    }
    firstNameInput.addEventListener('change', handleChange);
    lastNameInput.addEventListener('change', handleChange);
    
    Login or Signup to reply.
    1. IDs are specific. Use getElementById
    2. Use ONE event listener assigned OUTSIDE any other event listeners
    3. No need to addrow
    4. Use focus to be able to fill the table without the mouse
    const inputArticle = document.getElementById('input-article');
    const outputArticle = document.getElementById('output-article');
    const table = document.getElementById('table');
    const mySubmitButton = document.getElementById('mySubmit');
    
    let names = [];
    let rowNumber = 0;
    
    function addRow() {
      let row = table.insertRow(-1);
      let cell1 = row.insertCell(0);
      let cell2 = row.insertCell(1);
      let firstNameInput = document.createElement("input");
      let lastNameInput = document.createElement("input");
    
      firstNameInput.type = "text";
      firstNameInput.setAttribute('id', `firstName${rowNumber}`);
      cell1.appendChild(firstNameInput);
    
      lastNameInput.type = "text";
      lastNameInput.setAttribute('id', `lastName${rowNumber}`);
      cell2.appendChild(lastNameInput);
      firstNameInput.focus();
      rowNumber++;
    }
    
    const onRowChange = (e) => {
      const tgt = e.target;
      const inputs = e.target.closest('tbody').querySelectorAll('input')
      if ( [...inputs].every(input => input.value.trim() !== "")) addRow();
    };
    
    const mySubmit = (e) => {
      let confirmation = confirm("Are you sure you have all of the names?");
      if (confirmation) {
        inputArticle.classList.add("hidden");
        outputArticle.classList.remove("hidden");
      }
    };
    table.addEventListener('change', onRowChange);
    inputArticle.classList.remove("hidden");
    outputArticle.classList.add("hidden");
    mySubmitButton.addEventListener('click', mySubmit);
    
    addRow(); // Initial call to add the first row
    #input-article.hidden {
      display: none;
    }
    
    table {
      text-align: center;
      align-items: center;
    }
    
    th {
      width: 50vmin;
      height: 10vmin;
      font-size: 20pt;
      font-weight: 800;
    }
    
    input {
      width: 50vmin;
      height: 5vmin;
      text-align: center;
      align-items: center;
      font-size: 18pt;
      font-weight: 400;
      font-family: Georgia, 'Times New Roman', Times, serif;
      border: 0;
      padding: 0;
    }
    
    #buttons {
      width: 100vmin;
      height: 10vmin;
    }
    
    #submit {
      background-color: blue;
      color: white;
      border: 0;
      position: relative;
      left: 84%;
    }
    
    #output-article.hidden {
      display: none;
    }
    <article id="input-article">
      <table border="1">
        <tbody id="table">
          <tr>
            <th>First Name:</th>
            <th>Last Name:</th>
          </tr>
        </tbody>
      </table> <br>
    
      <div id="buttons">
        <button id="mySubmit">Submit</button>
      </div>
    </article>
    
    <article id="output-article">
      Output
    </article>
    
    <script src="try.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search