counter: with click, the number should increase by one

Viewed 54

I'm a beginner when it comes to Javascript. With click, the number should increase by one. I don't want to use tag IDs here, but as if made in class.

I am trying to give you a quick overview of the ClapsCounter here. The clap clicks are stored in the respective _ClapsCounter.txt file and the vote is stored in the browser localStorage as "applaudiert". Click on the counter to increase the value of all divs with the class "ClapsCounterCount".

 let clicks = document.querySelectorAll('.ClapsCounterTrigger');
 let count = Array.from(document.querySelectorAll('.ClapsCounterCount'));

 let TxtContainer = Array.from(document.querySelectorAll('.ClapsCounterTxtContainer'));
 let beforClick = "<span class=\"muted italic\">Applaudieren Sie diesen Artikel</span>";
 let afterClick = "<span class=\"success italic\">Danke für Ihren Applaus!</span>";
 let alreadyClick = "<span class=\"warning italic\">Danke, Sie haben schon applaudiert!</span>";

 let i;
 TxtContainer.forEach(i => i.innerHTML = beforClick);

// something wrong here!?
// take the current number from the .ClapsCounterCount
 let plus = count.forEach(i => i.innerHTML);

 for (let i = 0; i < clicks.length; i++) {

   clicks[i].onclick = function () {
    // after the click increase the current click number with 1
    count.forEach(i => i.innerHTML = ++plus);
    TxtContainer.forEach(i => i.innerHTML = afterClick);
  }
}
 <div class="ClapsCounter">
   <h4>View @media (min-width: 960px)</h4>
   <p><span class="ClapsCounterCount">123<!-- '.$count.' --></span> <span>Applause erhalten</span></p>
   <p class="ClapsCounterTxtContainer"></p>
   <button class="ClapsCounterTrigger">Count +1 Button</button>
 </div>

 <div class="ClapsCounter large">
   <h4>View @media (min-width: 1200px)</h4>
   <p><span class="ClapsCounterCount">123<!-- '.$count.' --></span> <span>Applause erhalten</span></p>
   <p class="ClapsCounterTxtContainer"></p>
   <button class="ClapsCounterTrigger">Count +1 Button</button>
 </div>

Wrong with these lines !?

    // something wrong here!?
    // take the current number from the .ClapsCounterCount
     let plus = count.forEach(i => i.innerHTML);

    // after the click increase the current click number with 1
     count.forEach(i => i.innerHTML = ++plus);

expected output before click

123

expected output after click

124

Please see it in JSFiddle

Update & Solved:

Thanks for your the answer from T.J. Crowder.

The line

count.forEach (i => i.innerHTML = ++ plus);

with this addition

count.forEach (element => element.innerHTML = parseInt (element.innerHTML, 10) + 1);

solved my problem.

1 Answers

Yes, as you've said in a comment, the problem is here:

let plus = count.forEach(i => i.innerHTML);

forEach doesn't return anything, so plus will always be undefined. ++undefined is NaN.

Instead of trying to store the number in advance, use it as it is when the click occurs. Also, I recommend parsing it intentionally rather than relying on implicit conversion from the string you get from innerHTML to a number:

count.forEach(element => element.innerHTML = parseInt(element.innerHTML, 10) + 1);

Here's y our code with that change (I also removed plus entirely):

let clicks = document.querySelectorAll('.ClapsCounterTrigger');
 let count = Array.from(document.querySelectorAll('.ClapsCounterCount'));

 let TxtContainer = Array.from(document.querySelectorAll('.ClapsCounterTxtContainer'));
 let beforClick = "<span class=\"muted italic\">Applaudieren Sie diesen Artikel</span>";
 let afterClick = "<span class=\"success italic\">Danke für Ihren Applaus!</span>";
 let alreadyClick = "<span class=\"warning italic\">Danke, Sie haben schon applaudiert!</span>";

 let i;
 TxtContainer.forEach(i => i.innerHTML = beforClick);

 for (let i = 0; i < clicks.length; i++) {

   clicks[i].onclick = function () {
    // after the click increase the current click number with 1
    count.forEach(element => element.innerHTML = parseInt(element.innerHTML, 10) + 1);
    TxtContainer.forEach(i => i.innerHTML = afterClick);
  }
}
<div class="ClapsCounter">
   <h4>View @media (min-width: 960px)</h4>
   <p><span class="ClapsCounterCount">123<!-- '.$count.' --></span> <span>Applause erhalten</span></p>
   <p class="ClapsCounterTxtContainer"></p>
   <button class="ClapsCounterTrigger">Count +1 Button</button>
 </div>

 <div class="ClapsCounter large">
   <h4>View @media (min-width: 1200px)</h4>
   <p><span class="ClapsCounterCount">123<!-- '.$count.' --></span> <span>Applause erhalten</span></p>
   <p class="ClapsCounterTxtContainer"></p>
   <button class="ClapsCounterTrigger">Count +1 Button</button>
 </div>

As you can see, it increments to 124 now.


FWIW, I've made a few other changes and marked them out with *** comments:

let clicks = document.querySelectorAll('.ClapsCounterTrigger');
let count = Array.from(document.querySelectorAll('.ClapsCounterCount'));

//*** Standard JavaScript naming is that you wouldn't use a capital letter at
// the beginning of `txtContainer`, so I've changed it throughout
let txtContainer = Array.from(document.querySelectorAll('.ClapsCounterTxtContainer'));
let beforClick = "<span class=\"muted italic\">Applaudieren Sie diesen Artikel</span>";
let afterClick = "<span class=\"success italic\">Danke für Ihren Applaus!</span>";
let alreadyClick = "<span class=\"warning italic\">Danke, Sie haben schon applaudiert!</span>";

// *** The `let i` that was here declared a variable that wasn't used; I
// removed it 
txtContainer.forEach(i => i.innerHTML = beforClick);

// *** I suspect you want to increase the counter only in the counter div
//  where the button was, rather than increasing all of them. To do that,
// I've replaced your loop with the following:
clicks.forEach(btn => btn.addEventListener("click", function() {
    // *** Within this callback, `this` refers to the button that was
    // clicked. To use that feature, notice that this is a traditional
    // `function` function, not an arrow function. But the element is also
    // available as `currentTarget` on the event object this function
    // receives, so if you wanted to use an arrow function, you'd accept
    // a parameter and use the `currentTarget` property of it instead..
    // Starting from the button that was clicked, we can find the ancestor
    // .ClapsCounter element, and then only update the counter and text inside
    // it.
    const container = this.closest(".ClapsCounter");
    if (container) {
        const counter = container.querySelector(".ClapsCounterCount");
        if (counter) {
            counter.innerHTML = parseInt(counter.innerHTML) + 1;
            if (txt) {
                const txt = container.querySelector(".ClapsCounterTxtContainer");
                txt.innerHTML = afterClick;
            }
        }
    }
}));
<div class="ClapsCounter">
   <h4>View @media (min-width: 960px)</h4>
   <p><span class="ClapsCounterCount">123<!-- '.$count.' --></span> <span>Applause erhalten</span></p>
   <p class="ClapsCounterTxtContainer"></p>
   <button class="ClapsCounterTrigger">Count +1 Button</button>
 </div>

 <div class="ClapsCounter large">
   <h4>View @media (min-width: 1200px)</h4>
   <p><span class="ClapsCounterCount">123<!-- '.$count.' --></span> <span>Applause erhalten</span></p>
   <p class="ClapsCounterTxtContainer"></p>
   <button class="ClapsCounterTrigger">Count +1 Button</button>
 </div>

Related