Reputation: 879
I have written code for a progress bar to increase dynamically when I clicked on a specific milestone.
When I click on a milestone I want the color to stay red but I can't add onclick
method to every div.
I have updated code ,i have inserted columns in a row so that i want keep progress bar in first column, but the dots are over flowing. can any one help?
var mileStones = Array.from(document.querySelectorAll('.primary-color'));
mileStones.forEach(elem => {
elem.onclick = function() {
const current = this;
let flag = false;
document.getElementById('pp').style.width = current.dataset.width + '%';
mileStones.forEach(elem => {
elem.classList.add('active');
if (flag) elem.classList.remove('active');
if (current.id === elem.id) flag = true;
});
}
});
.progress {
width: 100%;
height: 6px;
margin-top: 50px;
}
.progress-bar {
width: 50%;
background-color: #00A2DB;
}
#one,
#two,
#three,
#four,
#five {
position: absolute;
margin-top: -8px;
z-index: 1;
height: 20px;
width: 20px;
border-radius: 25px;
}
#one,
.percent {
left: 0%;
}
#two,
.percent1 {
left: 25%;
}
#three,
.percent2 {
left: 50%;
}
#four,
.percent3 {
left: 75%;
}
#five,
.percent4 {
left: 100%;
}
.primary-color {
background-color: pink;
}
.primary-color:active {
background-color: red;
}
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
</head>
<div class="row">
<div class="col-9">
<p>Business case completion:</p>
<div class="progress" id="progress">
<div class="primary-color" id="one" data-width="0"></div>
<div class="primary-color" id="two" data-width="25"></div>
<div class="primary-color" id="three" data-width="50"></div>
<div class="primary-color" id="four" data-width="75"></div>
<div class="primary-color" id="five" data-width="100"></div>
<div class="progress-bar" id="pp" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" onclick="progressBarTest()"></div>
</div>
</div>
<div class="col-3 align-self-end">
<p class="primary1"> ID 453</p>
</div>
</div>
Upvotes: 0
Views: 3011
Reputation: 21161
Just delegate the click event by listening for it in the progress bar itself (#progress__base
in the example below).
You can then check Event.target
to know which element was clicked and its index and use that to calculate the new progress percentage and add or remove an .active
class to all the milestones that come before or after the clicked one.
Actually, if you use Flexbox in your CSS, you can simplify your code a lot and make it work with any number of milestones without changing any CSS or JavaScript code, just adding more or less of them in the HTML:
const progressBase = document.getElementById('progress__base');
const progressBar = document.getElementById('progress__bar');
const progressPoints = Array.from(progressBase.children).slice(1);
progressBase.onclick = function(e) {
const target = e.target;
if (!target.classList.contains('progress__bullet')) {
// Ignore clicks on #progress__base and #progress__bar
return;
}
const index = progressPoints.indexOf(target);
progressBar.style.width = `${ 100 * index / (progressPoints.length - 1) }%`;
// Add the active class to all the ones that come before the
// clicked one, and the clicked one itself:
for (let i = 0; i <= index; ++i) {
progressPoints[i].classList.add('active');
}
// Remove the active class from all the ones that come after
// the clicked one:
for (let i = index + 1; i < progressPoints.length; ++i) {
progressPoints[i].classList.remove('active');
}
};
#progress__base {
position: relative;
width: 100%;
margin: 5px 0;
display: flex;
justify-content: space-between;
background: #EEE;
border-radius: 10px;
overflow: hidden;
}
#progress__bar {
position: absolute;
top: 0;
left: 0;
width: 0%;
height: 100%;
background: blue;
transition: width ease-in 250ms;
}
.progress__bullet {
height: 20px;
width: 20px;
border-radius: 25px;
background: pink;
box-shadow: 0 0 0 2px white;
cursor: pointer;
z-index: 1;
}
.progress__bullet:active,
.progress__bullet.active {
background: red;
}
<div id="progress__base">
<div id="progress__bar"></div>
<div class="progress__bullet active"></div>
<div class="progress__bullet"></div>
<div class="progress__bullet"></div>
<div class="progress__bullet"></div>
<div class="progress__bullet"></div>
</div>
Upvotes: 2
Reputation: 7686
You can create a generic method to set onclick for every miles stone, and you can use a class "active" to maintain the active style, you can also benefit from data attributes in order to make the function dynamic..
Edition To persist the milestones that are before the clicked one you can use a flag. in order to achieve this.
var mileStones = Array.from(document.querySelectorAll('.primary-color'));
mileStones.forEach(elem => {
elem.onclick = function() {
const current = this;
let flag = false;
document.getElementById('pp').style.width = current.dataset.width+'%';
mileStones.forEach(elem =>{
elem.classList.add('active');
if(flag) elem.classList.remove('active');
if(current.id === elem.id) flag = true;
});
}
});
.progress {
width: 100%;
height: 6px;
}
.progress-bar {
width: 50%;
background-color: #00A2DB;
}
#one,
#two,
#three,
#four,
#five {
position: absolute;
margin-top: -8px;
z-index: 1;
height: 20px;
width: 20px;
border-radius: 25px;
}
#one {
left: 0%;
}
#two {
left: 25%;
}
#three {
left: 50%;
}
#four {
left: 75%;
}
#five {
left: 100%;
}
.primary-color {
background-color: pink;
}
.primary-color:active, .active {
background-color: red;
}
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
</head>
<div class="progress">
<div class="primary-color" id="one" data-width="0"></div>
<div class="two primary-color" id="two" data-width="25"></div>
<div class="three primary-color" id="three" data-width="50"></div>
<div class="four primary-color" id="four" data-width="75"></div>
<div class="five primary-color" id="five" data-width="100"></div>
<div class="progress-bar" id="pp" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" onclick="progressBarTest()"></div>
</div>
Upvotes: 2