Home > Net >  why does this javascript code work differently? Is there any thing that I am missing?
why does this javascript code work differently? Is there any thing that I am missing?

Time:08-05

i dont' get why my javascript code works differently despite it looks like same to me. I am a beginner and I tried to figure out what is wrong and I couldn't. In one method which I have commented the code works in a way it should work while in other it looks like the code is broken. It works in way it shouldn't and I couldn't figure out why it is happening.

let smallCups = document.querySelectorAll(".cup-small")
let liters = document.getElementById("liters")
let percentage = document.getElementById("percentage")
let remained = document.getElementById("remained")

// smallCups.forEach(function (cup, idx) {
//   cup.addEventListener("click", function () {
//     highLightCups(idx)
//   })
// })

// function highLightCups(idx) {
//   if (smallCups[idx].classList.contains("full")) {
//     idx--
//   }

//   smallCups.forEach(function (cup, idx2) {
//     if (idx2 <= idx) {
//       cup.classList.add("full")
//     } else {
//       cup.classList.remove("full")
//     }
//   })
// }

smallCups.forEach(function(cup, idx) {
  cup.addEventListener("click", function() {
    if (smallCups[idx].classList.contains("full")) {
      idx--
    }
    smallCups.forEach(function(cup, idx2) {
      if (idx2 <= idx) {
        cup.classList.add("full")
      } else {
        cup.classList.remove("full")
      }
    })
  })
})
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

 :root {
  --border-color: #144fc6;
  --fill-color: #6ab3f8;
}

html {
  font-size: 62.5%;
  /* 1rem = 10px */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-size: 1.6rem;
  font-family: "Poppins", sans-serif;
  background-color: #3494e4;
  display: flex;
  flex-direction: column;
  align-items: center;
  color: #fff;
}

h1 {
  margin: 10px 0 0;
}

h3 {
  font-weight: 400;
  margin: 10px 0;
}

.cup {
  background-color: #fff;
  border: 4px solid var(--border-color);
  color: var(--border-color);
  border-radius: 0 0 40px 40px;
  height: 330px;
  width: 150px;
  margin: 30px 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.cup.cup-small {
  height: 95px;
  width: 50px;
  border-radius: 0 0 15px 15px;
  background-color: rgba(255, 255, 255, 0.9);
  cursor: pointer;
  font-size: 14px;
  align-items: center;
  justify-content: center;
  text-align: center;
  margin: 5px;
  transition: .3s ease;
}

.cups {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  width: 280px;
}

.cup.cup-small.full {
  background-color: var(--fill-color);
  color: #fff;
}

.remained {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  flex: 1;
  transition: .3s ease;
}

.remained span {
  font-size: 20px;
  font-weight: 600;
}

.remained small {
  font-size: 12px;
}

.percentage {
  background-color: var(--fill-color);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 3rem;
  height: 0;
  transition: .3s ease;
}

.text {
  text-align: center;
  margin: 0 0 5px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&display=swap" rel="stylesheet" />
  <link rel="stylesheet" href="style.css" />
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
</head>

<body>
  <h2>drink water</h2>
  <h3>goal : 2 liter</h3>

  <div >
    <div  id="remainded">
      <span id="liters">1.5l</span>
      <span>remained</span>
    </div>

    <div  id="percentage">20%</div>
  </div>

  <p >select how many glasses of water that you have drank</p>

  <div >
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
  </div>

  <script src="https://kit.fontawesome.com/d48313b36e.js" crossorigin="anonymous"></script>
  <script src="main.js"></script>
</body>

</html>

CodePudding user response:

The problem is idx.

In the commented version idx is passed to the function and is passed by value. A local variable (also called idx) is created. Any changes to the value of idx are not persisted between clicks.

In your version the variable idx is captured in a closure by the event handler . Each time the click handler runs it gets the value of the captured variable idx which is being updated by the code. The next time the handler runs it uses the updated value of idx and not the original value.

To fix your version you will have to create a copy of idx e.g. let index = idx; and use the variable index inside the click handler to make sure the value of idx never changes!

let smallCups = document.querySelectorAll(".cup-small")
let liters = document.getElementById("liters")
let percentage = document.getElementById("percentage")
let remained = document.getElementById("remained")

smallCups.forEach(function(cup, idx) {
  cup.addEventListener("click", function() {
    // use original value of idx but do not update it!
    let index = idx;
    if (smallCups[index].classList.contains("full")) {
      index--
    }
    smallCups.forEach(function(cup, idx2) {
      if (idx2 <= index) {
        cup.classList.add("full")
      } else {
        cup.classList.remove("full")
      }
    })
  })
})
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

 :root {
  --border-color: #144fc6;
  --fill-color: #6ab3f8;
}

html {
  font-size: 62.5%;
  /* 1rem = 10px */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-size: 1.6rem;
  font-family: "Poppins", sans-serif;
  background-color: #3494e4;
  display: flex;
  flex-direction: column;
  align-items: center;
  color: #fff;
}

h1 {
  margin: 10px 0 0;
}

h3 {
  font-weight: 400;
  margin: 10px 0;
}

.cup {
  background-color: #fff;
  border: 4px solid var(--border-color);
  color: var(--border-color);
  border-radius: 0 0 40px 40px;
  height: 330px;
  width: 150px;
  margin: 30px 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.cup.cup-small {
  height: 95px;
  width: 50px;
  border-radius: 0 0 15px 15px;
  background-color: rgba(255, 255, 255, 0.9);
  cursor: pointer;
  font-size: 14px;
  align-items: center;
  justify-content: center;
  text-align: center;
  margin: 5px;
  transition: .3s ease;
}

.cups {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  width: 280px;
}

.cup.cup-small.full {
  background-color: var(--fill-color);
  color: #fff;
}

.remained {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  flex: 1;
  transition: .3s ease;
}

.remained span {
  font-size: 20px;
  font-weight: 600;
}

.remained small {
  font-size: 12px;
}

.percentage {
  background-color: var(--fill-color);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 3rem;
  height: 0;
  transition: .3s ease;
}

.text {
  text-align: center;
  margin: 0 0 5px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&display=swap" rel="stylesheet" />
  <link rel="stylesheet" href="style.css" />
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
</head>

<body>
  <h2>drink water</h2>
  <h3>goal : 2 liter</h3>

  <div >
    <div  id="remainded">
      <span id="liters">1.5l</span>
      <span>remained</span>
    </div>

    <div  id="percentage">20%</div>
  </div>

  <p >select how many glasses of water that you have drank</p>

  <div >
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
    <div >250ml</div>
  </div>

  <script src="https://kit.fontawesome.com/d48313b36e.js" crossorigin="anonymous"></script>
  <script src="main.js"></script>
</body>

</html>

  • Related