javascriptobject-construction

How can I create new objects with user defined properties every time a function is called in JavaScript?


Apologies if this is a stupid question, I'm very much a beginner here.

I run a D&D game, and I thought a good thing to practice coding with would be a simple initiative tracker.

At the moment, I'm just trying to create a new object with user-defined properties for the name and initiative modifier. push it to the combatant array, and display it underneath the rest of the content every time the saveCombBtn is pressed. Here's the code I've got for it so far:

HTML:

<!DOCTYPE html>
<html>
<head>
    <title>Initiative Tracker</title>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Initiative Tracker</h1>
    <div id="canvas">
        <div class="CombInElCont">
            <input id="combNameInEl" placeholder="Combatant Name">
            <input id="combInitModInEl" placeholder="Initiative Modifier" type="Number">
            <button id="saveCombBtn">Save Combatant</button>
        </div>
    </div>
<script src="script.js"></script>
</body>
</html>

JavaScript:

// Gets initial elements
const canvas = document.querySelector('#canvas');
const combInElCont = document.querySelector('.combInElCont');
const combNameInEl = document.querySelector('#combNameInEl');
const combInitModInEl = document.querySelector('#combInitModInEl');
const saveCombBtn = document.querySelector('#saveCombBtn');
const combArray = [];


// Combatant Object Constructor
function Combatant(combName, combInitMod) {
    this.name = combName;
    this.initMod = combInitMod;
}    


// Reads user input, saves data to object, and pushes it to array 
saveCombBtn.addEventListener('click', saveCombatant);
function saveCombatant() {
    console.log('saveBtn pressed');
    let combName = combNameInEl.value;
    let combInitMod = combInitModInEl.value;

    let newComb = new Combatant(combName, combInitMod);
    combArray.push(newComb);
    combNameInEl.value = '';
    combInitModInEl.value = '';
    disCombInfo();
};

// Displays combatant info underneath inputs
function disCombInfo() {
    for (let i = 0; i < combArray.length; i++) {
        canvas.innerHTML += `
        <div class="combInfoDisp">
            <p>
                Combatant Name:<br>
                ${combArray[i].name}<br>
                Initiative Modifier:<br>
                ${combArray[i].initMod}
            </p>
        </div>
        `
        console.log(combArray[i]);
    };
};

The code works perfectly on the first button press, but won't even register that the button's been pressed a second time.

My only theory at the moment is that I can't create multiple objects of the same name (though I don't think that explains why the button doesn't even register being pressed a second time). Is there a way I can give the object a unique name every time the function is called, and is there anything else you can see that might be causing me issues?


Solution

  • Try this:

    // Gets initial elements
    const canvas = document.querySelector('#canvas');
    const combInElCont = document.querySelector('.combInElCont');
    const combNameInEl = document.querySelector('#combNameInEl');
    const combInitModInEl = document.querySelector('#combInitModInEl');
    const saveCombBtn = document.querySelector('#saveCombBtn');
    const combArray = [];
    
    // Combatant Object Constructor
    function Combatant(combName, combInitMod) {
        this.name = combName;
        this.initMod = combInitMod;
    }    
    
    
    // Reads user input, saves data to object, and pushes it to array 
    saveCombBtn.addEventListener('click', saveCombatant);
    function saveCombatant() {
        console.log('saveBtn pressed');
        let combName = combNameInEl.value;
        let combInitMod = combInitModInEl.value;
    
        let newComb = new Combatant(combName, combInitMod);
    
        combArray.push(newComb)
        disCombInfo(newComb);
    };
    
    // Displays combatant info underneath inputs
    function disCombInfo(newComb) {
        var combatant = document.createElement('div');
        combatant.classList.add('combInfoDisp');
        combatant.innerHTML = `
          <p>
          Combatant Name:<br>
          ${newComb.name}<br>
          Initiative Modifier:<br>
          ${newComb.initMod}
          </p>
        `
        canvas.appendChild(combatant);
        console.log(combArray);
    };
    <!DOCTYPE html>
    <html>
    <head>
        <title>Initiative Tracker</title>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <h1>Initiative Tracker</h1>
        <div id="canvas">
            <div class="CombInElCont">
                <input id="combNameInEl" placeholder="Combatant Name">
                <input id="combInitModInEl" placeholder="Initiative Modifier" type="Number">
                <button id="saveCombBtn">Save Combatant</button>
            </div>
        </div>
    <script src="script.js"></script>
    </body>
    </html>

    EDITED

    The problem with your original code is that it directly appends to the innerHTML of your canvas element, which messes up the eventListener of the button, since it is defined within the canvas. So my workaround consist mainly of leaving the innerHTML of the canvas untouched, and directly appending a new element which is created dynamically with javascript's createElement function.