When I count box which are checked, it counts plus one box

Tags: , ,



My web-app is about forecasting on sports games. My page shows all the matches and the points you can get out of each outcome from a match (Madrid = 12 points VS Barcelone = 15 points). So a user check a box from a match and select for him the right outcome. I would like each time the user check a box, to show him the number of boxes he checked.

Here is my Javascript to count the box checked :

    const updateCount = function() {
      var x = document.querySelectorAll(".square:checked").length;
      document.querySelector(".plus").innerHTML = x;
    };

Here is the HTML where the number of box checked will be displayed

<div class=" d-flex pt-2">
            <h3 class="typos">Matchs pronostiqu├ęs</h3>
            <h3 class="typos pts" style="font-weight: bold; padding-left: 5px;"><%= current_user.forecasts.where(confirmed: true, season_id: Season.last.id).count %>/50</h3>
            <span class="plus"></span>
          </div>

Here is my Javascript in order to know which game the user forecasted and which outcome he selected :

const selectOutcome = () => {
  const selects = document.querySelectorAll(".square");
  selects.forEach((outcome)=>{
    outcome.addEventListener("click",(event) => {
  $('input[type="checkbox"]').on('change', function() {
   $(this).siblings('input[type="checkbox"]').not(this).prop('checked', false);
});
      const result = event.currentTarget.dataset.outcome;
      console.log(result);
      const id = event.currentTarget.parentNode.dataset.id;
      console.log(id);
      const box = event.currentTarget.checked;
      console.log(box);
      const url = 'store_outcome?result='+result+'&match='+id+'&box='+box
      fetch(url)
        .then(response => response.json())
        .then((data) => {
      console.log(data);
      });
    });
  });
}

const validePanier = () => {
  const panier = document.getElementById('panier');
  panier.addEventListener("click", (event) =>{
    console.log("click")
    const player = document.getElementById('season_player').value;
    fetch('confirm_pending?player='+player)
    .then(response => response.json())
    .then((data) => {
    console.log(data);
    });
  })
}

Here is my HTML, for each match I have in my database, a match is going to appear in front in this way.

    <% @matches.each do |match| %>
          <% if Time.parse(match.kick_off) > Time.now && current_user.forecasts.find_by(match_id: match.id, confirmed: true).nil? && match.points_home.present? %>
          <% if match.sport == "football" %>
        <div class="d-flex justify-content-center mb-2 mt-2">
          <h4 class="typopo"><%= match.league %></h4>
        </div>
        <div class="d-flex justify-content-center mb-2 mt-2">
          <h3 class="tit"><%= DateTime.parse(match.kick_off).to_date%></h3><h3 class="typopo pl-2">-</h3>
          <h3 class="typopo pl-2"><%= match.kick_off.to_s.gsub("T", " ").split[1].gsub("+", " ").split[0]%></h3>
        </div>
        <div class="d-flex flex-row justify-content-around mb-4 mt-4" data-id="<%= match.id %>">
          <div class="d-flex flex-column align-items-center col-4">
            <div class="row">
              <h3 class="typopo"><%= image_tag "#{match.team_home_logo_url}", width: 50 %></h3>
            </div>
            <div class="row text-align-center">
              <h3 class="tit"><%= match.team_home %></h3>
            </div>
          </div>
          <div class="d-flex flex-column justify-content-center">
            <p class="typopo text-center">VS</p>
            <div class="d-flex flex-row align-items-center col-4">
              <div class="displaysquares" data-id="<%= match.id %>">
                <input type="checkbox" class="square" onclick="updateCount()" data-outcome="1"></input>
                <input type="checkbox" class="square" onclick="updateCount()" data-outcome="NULL"></input>
                <input type="checkbox" class="square" onclick="updateCount()" data-outcome="2"></input>
              </div>
            </div>
          </div>

There is a data-id. The purpose is when a user check a box, I can get the id of the match, in order to create the right forecast for the right game.

Answer

I would delegate instead of having inline event handlers

Here I COUNT the checkboxes – why do you not want the VALUE of a checked RADIO?

Note I wrapped all matches in <div id="matches">...</div>

document.getElementById("matches").addEventListener("change", function(e) {
  const tgt = e.target;
  if (tgt.classList.contains("square")) {
    const parent = tgt.closest(".displaysquares");
    var x = parent.querySelectorAll(".square:checked").length;
    document.querySelector(".plus").innerHTML += parent.dataset.id + ": " + x +"<br/>" ;
  }
})
<span class="plus"></span>
<div id="matches">
  <div class="d-flex justify-content-center mb-2 mt-2">
    <h4 class="typopo">League 1</h4>
  </div>
  <div class="d-flex justify-content-center mb-2 mt-2">
    <h3 class="tit">
      Some date
    </h3>
    <h3 class="typopo pl-2">-</h3>
    <h3 class="typopo pl-2">Some string</h3>
  </div>
  <div class="d-flex flex-row justify-content-around mb-4 mt-4" data-id="MATCH 1">
    <div class="d-flex flex-column align-items-center col-4">
      <div class="row">
        <h3 class="typopo">TEAM LOGO </h3>
      </div>
      <div class="row text-align-center">
        <h3 class="tit">Some other team string</h3>
      </div>
    </div>
    <div class="d-flex flex-column justify-content-center">
      <p class="typopo text-center">VS</p>
      <div class="d-flex flex-row align-items-center col-4">
        <div class="displaysquares" data-id="MATCH 1">
          <input type="checkbox" class="square" data-outcome="1">
          <input type="checkbox" class="square" data-outcome="NULL">
          <input type="checkbox" class="square" data-outcome="2">
        </div>
      </div>
    </div>
  </div>

  <div class="d-flex justify-content-center mb-2 mt-2">
    <h4 class="typopo">League 2</h4>
  </div>
  <div class="d-flex justify-content-center mb-2 mt-2">
    <h3 class="tit">
      Some date
    </h3>
    <h3 class="typopo pl-2">-</h3>
    <h3 class="typopo pl-2">Some string</h3>
  </div>
  <div class="d-flex flex-row justify-content-around mb-4 mt-4" data-id="MATCH 2">
    <div class="d-flex flex-column align-items-center col-4">
      <div class="row">
        <h3 class="typopo">TEAM LOGO </h3>
      </div>
      <div class="row text-align-center">
        <h3 class="tit">Some other team string</h3>
      </div>
    </div>
    <div class="d-flex flex-column justify-content-center">
      <p class="typopo text-center">VS</p>
      <div class="d-flex flex-row align-items-center col-4">
        <div class="displaysquares" data-id="MATCH 2">
          <input type="checkbox" class="square" data-outcome="1">
          <input type="checkbox" class="square" data-outcome="NULL">
          <input type="checkbox" class="square" data-outcome="2">
        </div>
      </div>
    </div>
  </div>
</div>

Using Radios instead

const matches = document.getElementById("matches")
matches.addEventListener("change", function(e) {
  const tgt = e.target;
  if (tgt.classList.contains("square")) {
    var x = [...matches.querySelectorAll(".square:checked")].map(chk => chk.closest(".displaysquares").dataset.id + ": "+chk.dataset.outcome)
    document.querySelector(".plus").innerHTML = x.join("<br/>");
  }
})
<span class="plus"></span>
<div id="matches">
  <div class="d-flex justify-content-center mb-2 mt-2">
    <h4 class="typopo">League 1</h4>
  </div>
  <div class="d-flex justify-content-center mb-2 mt-2">
    <h3 class="tit">
      Some date
    </h3>
    <h3 class="typopo pl-2">-</h3>
    <h3 class="typopo pl-2">Some string</h3>
  </div>
  <div class="d-flex flex-row justify-content-around mb-4 mt-4" data-id="MATCH 1">
    <div class="d-flex flex-column align-items-center col-4">
      <div class="row">
        <h3 class="typopo">TEAM LOGO </h3>
      </div>
      <div class="row text-align-center">
        <h3 class="tit">Some other team string</h3>
      </div>
    </div>
    <div class="d-flex flex-column justify-content-center">
      <p class="typopo text-center">VS</p>
      <div class="d-flex flex-row align-items-center col-4">
        <div class="displaysquares" data-id="MATCH 1">
          <input type="radio" name="outcome1" class="square" data-outcome="1">
          <input type="radio" name="outcome1" class="square" data-outcome="NULL">
          <input type="radio" name="outcome1" class="square" data-outcome="2">
        </div>
      </div>
    </div>
  </div>

  <div class="d-flex justify-content-center mb-2 mt-2">
    <h4 class="typopo">League 2</h4>
  </div>
  <div class="d-flex justify-content-center mb-2 mt-2">
    <h3 class="tit">
      Some date
    </h3>
    <h3 class="typopo pl-2">-</h3>
    <h3 class="typopo pl-2">Some string</h3>
  </div>
  <div class="d-flex flex-row justify-content-around mb-4 mt-4" data-id="MATCH 2">
    <div class="d-flex flex-column align-items-center col-4">
      <div class="row">
        <h3 class="typopo">TEAM LOGO </h3>
      </div>
      <div class="row text-align-center">
        <h3 class="tit">Some other team string</h3>
      </div>
    </div>
    <div class="d-flex flex-column justify-content-center">
      <p class="typopo text-center">VS</p>
      <div class="d-flex flex-row align-items-center col-4">
        <div class="displaysquares" data-id="MATCH 2">
          <input type="radio" name="outcome2" class="square" data-outcome="1">
          <input type="radio" name="outcome2" class="square" data-outcome="NULL">
          <input type="radio" name="outcome2" class="square" data-outcome="2">
        </div>
      </div>
    </div>
  </div>
</div>


Source: stackoverflow