1

I'm not entirely sure how to ask this question. I know there's an answer out there somewhere but I can't for the life of me figure out / remember the terminology for what I'm trying to achieve.

I have profile cards written in HTML, all with the class name "card". Within each card are two numbers. I want to be able to display a progress bar specific to the % relationship of the numbers within each INDIVIDUAL card.

So, my code is:

<div class="card">
<p class="nameTitle">NAME 1</p>
<p class="cardTarget">20</p>
<p class="cardCurrent">10</p>
<div class="progBar"></div>
</div>

<div class="card">
<p class="nameTitle">NAME 2</p>
<p class="cardTarget">20</p>
<p class="cardCurrent">5</p>
<div class="progBar"></div>
</div>

What I'm hoping to achieve is for Javascript to acess the cardTarget and cardCurrent numbers of nameTitle: NAME 1, then output a percentage to progBar of the same card, and to do the same thing for nameTitle: NAME 2.

So that progBar of nameTitle: NAME1 will equal 50%, and progBar of nameTitle: NAME 2 will equal 25%.

I know how to access the elements, and I know how to do the calculations to convert to a percentage, what I don't know is how to (essentially) bind the elements to card without affecting other card because they are all assigned the same classnames.

I hope that makes sense, and thanks in advance for your help.

Kirk
  • 23
  • 5
  • I'm afraid it isn't clear what you're asking here (not least because you have two `NAME 1`s and no `NAME 2`). Could you please add the code where you're trying to access the elements? – T.J. Crowder Aug 10 '18 at 16:42
  • Did you try assigning them unique ids? use then `document.getElementById()` and you can access the exact element you want. – joseatchang Aug 10 '18 at 16:43
  • 1
    @joseatchang - No need for unique IDs when you have a DOM structure to work with. – T.J. Crowder Aug 10 '18 at 16:45
  • 1
    @T.J.Crowder Yes apologies for the mess. I have edited to correct it. But your answer below solved it thank you – Kirk Aug 10 '18 at 17:07

2 Answers2

1

I think you're probably looking for Element#querySelector, which lets you find an element within another element. (There's also Element#querySelectorAll to find a list.)

So for instance, to update those cards:

document.querySelectorAll(".card").forEach(card => {
    const cardTarget = card.querySelector(".cardTarget");
    const cardCurrent = card.querySelector(".cardCurrent");
    const progBar = card.querySelector(".progBar");
    const percent = (cardCurrent.textContent / cardTarget.textContent) * 100; // Or whatever
    progBar.setSomethingToReflectThatPercentage();
});

Live Example:

setTimeout(() => {
  document.querySelectorAll(".card").forEach(card => {
      const cardTarget = card.querySelector(".cardTarget");
      const cardCurrent = card.querySelector(".cardCurrent");
      const progBar = card.querySelector(".progBar");
      const percent = (cardCurrent.textContent / cardTarget.textContent) * 100; // Or whatever
      progBar.innerHTML = percent;
  });
}, 500);
<div class="card">
<p class="nameTitle">NAME 1</p>
<p class="cardTarget">20</p>
<p class="cardCurrent">10</p>
<div class="progBar">--</div>
</div>

<div class="card">
<p class="nameTitle">NAME 2</p>
<p class="cardTarget">20</p>
<p class="cardCurrent">5</p>
<div class="progBar">--</div>
</div>

Side note: That uses forEach on the NodeList returned by querySelectorAll. That's a relatively-recent addition to NodeList; if you find you need to polyfill it for your target environments, see this answer.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

Perhaps something like this can get you started. Note the offsets are a bit arbitrary, and I'm sure you have your own styling:

for (const e of document.getElementsByClassName("card")) {
  const target = +(e.querySelector(".cardTarget").innerText);
  const current = +(e.querySelector(".cardCurrent").innerText);
  const bar = e.querySelector(".progBar");
  bar.style.width = current / target * 300 + "px";
  bar.innerText = current * 5 / (target * 5) * 100 + "%";  
}
.progBar {
  height: 20px;
  background: #000;
  color: #fff;
}
<div class="card">
  <p class="nameTitle">NAME 1</p>
  <p class="cardTarget">20</p>
  <p class="cardCurrent">10</p>
  <div class="progBar"></div>
</div>

<div class="card">
  <p class="nameTitle">NAME 1</p>
  <p class="cardTarget">20</p>
  <p class="cardCurrent">5</p>
  <div class="progBar"></div>
</div>
ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • 1
    Just a side note: Although **some** implementations may make the `HTMLCollection` returned by `getElementsByClassName` iterable (current Chrome and Firefox do), [the spec](https://dom.spec.whatwg.org/#interface-htmlcollection) doesn't mark them as iterable and not all implementations add it (Edge doesn't, for instance). (This is as opposed to the [`NodeList`](https://dom.spec.whatwg.org/#interface-nodelist) from `querySelectorAll`, which *is* specified as iterable [now].) `for-of` only works on iterable objects. – T.J. Crowder Aug 10 '18 at 17:19
  • @T.J.Crowder Good to know, thanks! Either a traditional for loop or your version with `forEach` works too. – ggorlen Aug 10 '18 at 17:33