I have 5 circles to click. User can select only one. My problem is that I can't deselect previous circle and remove its data-value
from variable.
How can I handle it?
HTML
<div class="question">
<h3>' + test + '</h3>
<div class="row" style="padding-top:50px;">
<div class="col-xl-4 col-lg-3 col-md-2 col-sm-2 col-xs-3 text-center"> <span>Całkowicie nietrafnie mnie opisuje</span> </div>
<div class="col-xl-4 col-lg-6 col-md-8 col-sm-8 col-xs-6 text-center">
<div class="circles">
<div class="numberCircle" data-value="1">1</div>
<div class="numberCircle" data-value="2">2</div>
<div class="numberCircle" data-value="3">3</div>
<div class="numberCircle" data-value="4">4</div>
<div class="numberCircle" data-value="5">5</div>
</div>
</div>
<div class="col-xl-4 col-lg-3 col-md-2 col-sm-2 col-xs-3 text-center"><span>całkowicie trafnie mnie opisuje</span></div>
</div>
</div>
JS
pinEventAction = function (e) {
var progressBar = document.querySelector('#progressBar .bar');
var circles = document.querySelectorAll('.question .circles .clicked');
if (e.target.hasAttribute('data-value')) {
values += Number(e.target.getAttribute('data-value'));
e.target.className += ' clicked';
e.target.parentNode.className += ' checked';
width += 2;
progressBar.style.width = width + '%';
}
if (e.target.classList.contains('clicked')) {
e.target.classList.remove('clicked')
}
console.log('score: ' + values);
};
handleClickAndProgressBar = function () {
var progressBar = document.querySelector('#progressBar .bar');
var circles = document.querySelectorAll('.question .circles');
for (var i = 0; i < circles.length; i++) {
circles[i].addEventListener('click', pinEventAction);
}
};
No need to add an eventListener on each circle, you can add an eventListener to an ancestor node instead. By using event.target
property, you can determine which node was clicked. Read on Event Delegation for details.
The behavior desired for the circles is like a group of radio buttons that share the same name attribute (only one can be checked). I changed the circles into a radio/label pair then wrapped them into a <fieldset>
and a <form>
. By doing this, saves you from writing code for the behavior previously mentioned.
This demo does the following:
var form = document.forms[0];
form.addEventListener('click', circle, false);
function circle(e) {
if (e.target !== e.currentTarget) {
var val = this.elements.view;
var tgt = e.target;
if (tgt.tagName === 'FIELDSET') {
return;
}
if (tgt.classList.contains('act')) {
tgt.classList.remove('act');
val.value = 0;
} else if (!tgt.classList.contains('act')) {
tgt.classList.add('act');
val.value = tgt.value;
}
} else {
if (val.value === undefined) {
val.value = 0;
}
return false;
}
e.stopPropagation();
}
.rad {
display: none
}
.l {
background: black;
color: gold;
border-radius: 50%;
width: 24px;
height: 24px;
cursor: pointer;
margin: 0 auto;
padding-top: 3px;
display: block;
}
.rad:checked+label.l.act {
color: cyan
}
.rad:checked+label.l.act::before {
content: '<'
}
.rad:checked+label.l.act::after {
content: '>'
}
#view {
color: tomato;
font-weight: 900
}
<link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet'>
<div class="question">
<h3>' + test + '</h3>
<div class="row" style="padding-top:50px;">
<div class="col-xs-3 text-center"> <span>Całkowicie nietrafnie mnie opisuje</span> </div>
<form class="col-xs-6 text-center">
<output id='view'>0</output>
<fieldset class="circles">
<input id='rad1' class='rad' name='rad' type='radio' value="1">
<label class="l" for='rad1'>1</label>
<input id='rad2' class='rad' name='rad' type='radio' value="2">
<label class="l" for='rad2'>2</label>
<input id='rad3' class='rad' name='rad' type='radio' value="3">
<label class="l" for='rad3'>3</label>
<input id='rad4' class='rad' name='rad' type='radio' value="4">
<label class="l" for='rad4'>4</label>
<input id='rad5' class='rad' name='rad' type='radio' value="5">
<label class="l" for='rad5'>5</label>
</fieldset>
</form>
<div class="col-xs-3 text-center"><span>całkowicie trafnie mnie opisuje</span></div>
</div>
</div>