Search code examples
javascripthtmlcounter

How to get Buttons Enabled? (logic issue?)


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>


Solution

  • my 2 cents... :)

    Avoid duplicating information; like here with your list of HTML buttons and your array of JS objects containing your Teams [name, scores+/- ]. Prefer to generate one from the other. I chose here to generate the sequence of HTML buttons from the array, following the data-driven principle; which allows me to add the btnUI property in connection with the button added on the user interface. See: Teams.forEach( team => // generate teams buttons...

    then you will naturally need a function to update the value of the scores on the interface, here the function setButtonTeamScore( teamBtn, score_W, score_L )

    Still in the spirit of avoiding duplication of information, I use here a CSS ::before on the label of the teams, which also allows to make a left justification and to align the scores on the right.

    As for the distribution by pairs of teams it is done automatically since the available width allows to fit only 2 on each line.

    const
      resetButton  = document.querySelector('#resetButton')
    , groupButtons = document.querySelector('fieldset')
    , Teams = 
        [ { 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 }
        ];
    
    Teams.forEach( team =>  // generate teams buttons...
      {
      team.btnUI                  = document.createElement('button'); // add property 'btnUI' to retrieve UI his button
      team.btnUI.textContent      = 'Wins: 0 - Losses: 0';
      team.btnUI.dataset.teamName = team.name; // set data-team-name attribute
      groupButtons.append(team.btnUI);
      })
    
    resetButton.addEventListener('click', () =>
      {
      Teams.forEach( team => 
        {
        team.wins   = 0;
        team.losses = 0;
        setButtonTeamScore( team.btnUI, 0, 0 ).classList.remove('noMoreClick');
        })
      });
    
    groupButtons.addEventListener('click', evt => // change score... (event delegation method)
      {
      if (!evt.target.matches('button[data-team-name]')) return; // reject wrong places of click
    
      let 
        winIndx = Teams.findIndex( team => team.name === evt.target.dataset.teamName ) // determine which team is click-concern
      , looIndx = Boolean(winIndx %2) ? (winIndx -1) : (winIndx +1)                    // determine opponent team index
      , btn_W   = setButtonTeamScore( Teams[winIndx].btnUI, ++Teams[winIndx].wins, Teams[winIndx].losses )
      , btn_L   = setButtonTeamScore( Teams[looIndx].btnUI, Teams[looIndx].wins, --Teams[looIndx].losses )
        ;
      if (btn_L.disabled)
        btn_W.classList.add('noMoreClick');
      });
    
    function setButtonTeamScore( teamBtn, score_W, score_L )
      {
      teamBtn.textContent = score_L <= -2 
                          ? 'Eliminated' 
                          : `Wins: ${score_W} - Losses: ${score_L}`;
                          
      teamBtn.disabled    = ( score_L <= -2 );
      
      return teamBtn;  // for chaining methods.
      }
    #resetButton    { padding: .3rem .6rem; margin: .3rem; }
    fieldset        { padding: 1rem 0 0 1rem; width: 39.5rem; }
    fieldset button {
      width      : 18.7rem; 
      margin     : 0 1rem 1rem  0; 
      cursor     : pointer; 
      text-align : right;
      }
    fieldset button::before {
      content     : attr(data-team-name) ' :';
      font-weight : bold;
      float       : inline-start;
      }
    fieldset  button.noMoreClick { 
      pointer-events : none;
      cursor         : default;
      }
    fieldset button.noMoreClick::before {
      background-color : gold;
      }
    fieldset  button:disabled { 
      color  : red;
      cursor : not-allowed;
      }
    <button id="resetButton">Reset All Counters</button>
    <fieldset>
    </fieldset>