Enable Buttons – How to Fix Button Enable Logic Issues in JavaScript and HTML

counterhtmljavascript

I currently have a program with some teams that are in pairs. Clicking on a team increases the Wins of the team being clicked, and increases the Losses of the pair it is linked to. A team with two losses is disabled and changes their text to "Eliminated".

I have a reset button that is supposed to clear all of the counters and, in theory, by clearing the counters the disabled buttons should be reenabled again. However, this is not the case, they stay disabled and their text switches back to the team name. How do I keep my buttons enabled after being reset?

Any input would be greatly appreciated 🙂

let groups = [{
    name: "Chaos Coordinators",
    wins: 0,
    losses: 0
  },
  {
    name: "Sofa King Awesome",
    wins: 0,
    losses: 0
  },
  {
    name: "The Nerd Herd",
    wins: 0,
    losses: 0
  },
  {
    name: "The Laughing Stock",
    wins: 0,
    losses: 0
  },
  {
    name: "Brainy Bunch Gone Wild",
    wins: 0,
    losses: 0
  },
  {
    name: "Cereal Killers",
    wins: 0,
    losses: 0
  },
  {
    name: "The Mismatched Socks",
    wins: 0,
    losses: 0
  },
  {
    name: "The Awkward Turtles",
    wins: 0,
    losses: 0
  }
];


// Create pairs from the groups
function makeMatches(array) {
  return array.map((_, i) => (i % 2 === 0) ? [array[i], array[i + 1]] : []).filter(v => v.length === 2);
}

let matches = makeMatches(groups);

// Create a map of team names to their index
const groupIndexMap = {};
groups.forEach((group, index) => {
  groupIndexMap[group.name] = index;
});

// Function to handle button clicks
function handleButtonClick(groupName) {
  const matchIndex = groupIndexMap[groupName];
  const match = matches.find(match => match.some(group => group.name === groupName));


  if (!match) return;

  match.forEach((group, button) => {
    if (group.name === groupName) {
      group.wins += 1;
    } else if (group.losses < 2) {
      group.losses += 1;
    }
  });

  updateButtonTexts();
  console.log(groups);
}

// Function to update button texts
function updateButtonTexts() {
  groups.forEach((group, index) => {
    const button = document.getElementById(`button${index + 1}`);
    if (button) {
      button.textContent = `${group.name} - Wins: ${group.wins} - Losses: ${group.losses}`;
    }
    if (group.losses == 2) {
      button.textContent = 'Eliminated';
      button.disabled = true;
    }
  });
}

// Function to reset all counters
function resetCounters() {
  groups.forEach(group => {
    group.wins = 0;
    group.losses = 0;
  });
  updateButtonTexts();
}


// Initialize button click handlers
function initializeButtons() {
  groups.forEach((group) => {
    const button = document.querySelector(`[data-team-name='${group.name}']`);
    if (button) {
      button.onclick = () => handleButtonClick(group.name);
    }
  });

  // Initialize reset button handler
  document.getElementById('resetButton').onclick = resetCounters;

  // Initial update of button texts
  updateButtonTexts();
}

// Initial render and setup
initializeButtons();
#group-buttons {
  position: relative;
  /* Container should be relative for positioning buttons absolutely */
  width: 100%;
  height: 500px;
  /* Adjust height as needed */
  border: 1px solid #ccc;
}

.group-button {
  position: absolute;
  /* Allows for free positioning */
  cursor: pointer;
  /* Indicates the element is clickable */
  padding: 10px;
  background: #f0f0f0;
  border: 1px solid #ddd;
  border-radius: 5px;
}


/* Example styles for individual buttons */

#button1 {
  top: 50px;
  left: 50px;
}

#button2 {
  top: 50px;
  left: 200px;
}

#button3 {
  top: 150px;
  left: 50px;
}

#button4 {
  top: 150px;
  left: 200px;
}

#button5 {
  top: 250px;
  left: 50px;
}

#button6 {
  top: 250px;
  left: 200px;
}

#button7 {
  top: 350px;
  left: 50px;
}

#button8 {
  top: 350px;
  left: 200px;
}
<button id="resetButton">Reset All Counters</button>
<div id="group-buttons">
  <button id="button1" class="group-button" data-team-name="Chaos Coordinators">Chaos Coordinators - Wins: 0 - Losses: 0</button>
  <button id="button2" class="group-button" data-team-name="Sofa King Awesome">Sofa King Awesome - Wins: 0 - Losses: 0</button>
  <button id="button3" class="group-button" data-team-name="The Nerd Herd">The Nerd Herd - Wins: 0 - Losses: 0</button>
  <button id="button4" class="group-button" data-team-name="The Laughing Stock">The Laughing Stock - Wins: 0 - Losses: 0</button>
  <button id="button5" class="group-button" data-team-name="Brainy Bunch Gone Wild">Brainy Bunch Gone Wild - Wins: 0 - Losses: 0</button>
  <button id="button6" class="group-button" data-team-name="Cereal Killers">Cereal Killers - Wins: 0 - Losses: 0</button>
  <button id="button7" class="group-button" data-team-name="The Mismatched Socks">The Mismatched Socks - Wins: 0 - Losses: 0</button>
  <button id="button8" class="group-button" data-team-name="The Awkward Turtles">The Awkward Turtles - Wins: 0 - Losses: 0</button>
</div>

Best Answer

Use HTMLButtonElement's disabled property, set to a boolean value.


The code seems a bit too complicated and there are some non-addressed issues:

  • instead of creating an Array with pairs, use a different strategy: linked (graph) nodes. Clone the data, then each team Object should have an opponent property pointing to the opposing team Object, and vice-versa — by using: team.opponent = teams[i + (i % 2 === 0 ? 1 : -1)]; or if you like: team.opponent = teams[i + 1 - i % 2 * 2];
  • disable both buttons, not only the one of the losing party.
  • create a structuredClone to not pollute the original data - this way you don't need to do heavy resets - just reuse the original initial data.
  • prepopulated HTML is not necessary, create the buttons dynamically!

Simplified example:

// Data
const groups = [ {name: "Chaos Coordinators", wins: 0, losses: 0}, {name: "Sofa King Awesome", wins: 0, losses: 0}, {name: "The Nerd Herd", wins: 0, losses: 0}, {name: "The Laughing Stock", wins: 0, losses: 0}, {name: "Brainy Bunch Gone Wild", wins: 0, losses: 0}, {name: "Cereal Killers", wins: 0, losses: 0}, {name: "The Mismatched Socks", wins: 0, losses: 0}, {name: "The Awkward Turtles", wins: 0, losses: 0}];

// DOM helpers 
const el = (sel, par = document) => par.querySelector(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);

// App
const max = 2; // Max losses. SET AS DESIRED
const elGroupButtons = el("#group-buttons");

const updateButton = (team) => {
  const text = team.losses === max ? "Eliminated" : `Wins: ${team.wins} - Losses: ${team.losses}`;
  team.button.textContent = `${team.name} - ${text}`;
  team.button.disabled = team.losses === max || team.opponent.losses === max;
  team.button.classList.toggle("is-eliminated", team.losses === max);
};

const updateScore = (team, score = 1) => {
  team.wins += score;
  team.opponent.losses += score;
  updateButton(team);
  updateButton(team.opponent);
};

const makeMatches = (array) => {
  elGroupButtons.innerHTML = ""; // Cleanup
  // Let's clone data and recreate the buttons
  structuredClone(array).forEach((team, i, teams) => {
    team.opponent = teams[i + (i % 2 === 0 ? 1 : -1)];
    team.button = elNew("button", {
      className: "group-button",
      onclick() { updateScore(team); }
    });
    updateButton(team); // Initial button text
    elGroupButtons.append(team.button);
  });
};

// Init and Reset event
const matches = makeMatches(groups);
el("#resetButton").addEventListener("click", () => makeMatches(groups));
/*QuickReset*/ * { margin: 0; box-sizing: border-box; }

#group-buttons {
  position: relative;
  border: 1px solid #888;
  display: flex;
  flex-flow: row wrap;
  padding: 0.5em;
  gap: 0.5em;
  
  & .group-button {
    flex: 0 0 calc(50% - 0.3em);
    padding: 1em;

    &.is-eliminated {
      color: #f008;
    }
  }
}
<button id="resetButton">RESET</button>
<div id="group-buttons"></div>