Night
Night

Reputation: 61

How can I make a progress bar that changes according to a specific input number variable?

I wanted to make something that changed when I pressed enter in a input number variable for the value of the progress bar, and another input variable for the max of the progress bar, kinda like this:

Progress bar example

But, these values won't always be the same, so, that's why I wanted to know how to sync the input vars with the progress bar.

I'm really new to coding and I don't know JavaScript yet. I am still going to check it out, but I don't wanna learn everything about it just for one thing.

The code for the HTML I made is this:

<div id="lifepog">
    <input type="number" class="currentlife" max="20" min="0" value="0">
    <div id="lifeslash" contenteditable="false">
        <p>/</p>
    </div>
    <input type="number" class="totallife" max="20" min="0" value="0">
</div>
<div id="lifebar">
    <progress value="10" max="20" class="barlife"></progress>
</div>

Upvotes: 5

Views: 1828

Answers (1)

Dan Knights
Dan Knights

Reputation: 8378

You could listen for the input event and update the progress bar's attributes based off the value of each number input:

// Select the progress bar by its class
const progress = document.querySelector('.barlife');

// Set the progress bar's value based off the top input
const numerator = (e) => {
  progress.value = e.target.value;
}

// Set the progress bars max value based off the bottom input
const denominator = (e) => {
  progress.max = e.target.value;
}
<div id="lifepog">
  <input oninput="numerator(event)" type="number" class="currentlife" max="20" min="0" value="10">
  <div id="lifeslash" contenteditable="false">
    <p>/</p>
  </div>
  <input oninput="denominator(event)" type="number" class="totallife" max="20" min="0" value="20">
</div>
<div id="lifebar">
  <progress value="10" max="20" class="barlife"></progress>
</div>


For multiple progress bars you could pass an index to each function:

// Select the progress bar by its class
const progressBars = document.querySelectorAll('.barlife');

// Set the progress bar's value based off the top input
const numerator = (e, index) => {
  progressBars[index].value = e.target.value;
}

// Set the progress bars max value based off the bottom input
const denominator = (e, index) => {
  progressBars[index].max = e.target.value;
}
<div id="lifepog">
  <input oninput="numerator(event, 0)" type="number" class="currentlife" max="20" min="0" value="10">
  <div id="lifeslash" contenteditable="false">
    <p>/</p>
  </div>
  <input oninput="denominator(event, 0)" type="number" class="totallife" max="20" min="0" value="20">
</div>
<div id="lifebar">
  <progress value="10" max="20" class="barlife"></progress>
</div>

<div id="lifepog">
  <input oninput="numerator(event, 1)" type="number" class="currentlife" max="20" min="0" value="10">
  <div id="lifeslash" contenteditable="false">
    <p>/</p>
  </div>
  <input oninput="denominator(event, 1)" type="number" class="totallife" max="20" min="0" value="20">
</div>
<div id="lifebar">
  <progress value="10" max="20" class="barlife"></progress>
</div>

<div id="lifepog">
  <input oninput="numerator(event, 2)" type="number" class="currentlife" max="20" min="0" value="10">
  <div id="lifeslash" contenteditable="false">
    <p>/</p>
  </div>
  <input oninput="denominator(event, 2)" type="number" class="totallife" max="20" min="0" value="20">
</div>
<div id="lifebar">
  <progress value="10" max="20" class="barlife"></progress>
</div>


Now, for animation, you'll have to change things up a bit. You can't animate the progress element as it's a native element of the browser.

What you'll need is a div to mimic the behaviour of a progress bar:

const progress = document.getElementById('lifebar-inner');
const numeratorInput = document.querySelector('.currentlife');
const denominatorInput = document.querySelector('.totallife');

/* Set the max-width by calculating what percentage 
  the top input is of the bottom input */
const setProgress = () => {
  progress.style.maxWidth = `
    ${(numeratorInput.value / denominatorInput.value) * 100}%
  `;
}
#lifebar {
  margin: 10px;
  height: 10px;
  width: 200px;
  border: 1px solid grey;
  border-radius: 10px;
  overflow: hidden;
}

#lifebar-inner {
  background-color: lightblue;
  height: 100%;
  width: 100%;
  max-width: 50%;
  /* Transition the max-width property, 
    as it's smoother than transitioning the width property */
  transition: max-width 0.35s cubic-bezier(0.9, 0.4, 0.6, 0.7);
}
<div id="lifepog">
  <input oninput="setProgress()" type="number" class="currentlife" max="20" min="0" value="10">
  <div id="lifeslash" contenteditable="false">
    <p>/</p>
  </div>
  <input oninput="setProgress()" type="number" class="totallife" max="20" min="0" value="20">
</div>
<div id="lifebar">
  <div id="lifebar-inner" />
</div>

Upvotes: 3

Related Questions