Issue
I'm working on a HTML and JavaScript form for a personality test, and I'm encountering issues with validation. The form has multiple questions with both "MOST" and "LEAST" radio button options.
Issue 1: I want to alert the user if they select the same answer (either "MOST" or "LEAST") for a question.
I've tried implementing various solutions, but I'm still facing problems.
I aim to alert users if they selected the same answer (either "MOST" or "LEAST") for a question.
I've added the screenshot of the HTML for 1 question HTML Question
This is the Javascript:
`var DiscModule = (function() {
var d, i, s, c, d2, i2, s2, c2;
function getScores() {
d = i = s = c = 0;
var inputs = document.querySelectorAll('input[type="radio"]');
for (var count = 0, l = inputs.length; count < l; count++) {
if (inputs[count].checked) {
switch (inputs[count].value) {
case "d-most": d++; break;
case "i-most": i++; break;
case "s-most": s++; break;
case "c-most": c++; break;
case "d-least": d--; break;
case "i-least": i--; break;
case "s-least": s--; break;
case "c-least": c--; break;
}
}
}
// checks if all questions are answered
return (d !== 0 && i !== 0 && s !== 0 && c !== 0);
}
// calculations for the test
function calculateWeightedScores() {
if (d >= 6) d2 = 7;
else if (d >= -1) d2 = 6;
else if (d >= -5) d2 = 5;
else if (d >= -9) d2 = 4;
else if (d >= -13) d2 = 3;
else if (d >= -16) d2 = 2;
else d2 = 1;
if (i >= 8) i2 = 7;
else if (i >= 5) i2 = 6;
else if (i >= 2) i2 = 5;
else if (i >= -1) i2 = 4;
else if (i >= -4) i2 = 3;
else if (i >= -8) i2 = 2;
else i2 = 1;
if (s >= 12) s2 = 7;
else if (s >= 8) s2 = 6;
else if (s >= 5) s2 = 5;
else if (s >= 1) s2 = 4;
else if (s >= -2) s2 = 3;
else if (s >= -7) s2 = 2;
else s2 = 1;
if (c >= 6) c2 = 7;
else if (c >= 3) c2 = 6;
else if (c >= -1) c2 = 5;
else if (c >= -3) c2 = 4;
else if (c >= -7) c2 = 3;
else if (c >= -11) c2 = 2;
else c2 = 1;
}
function createCharts() {
var total = 7;
document.querySelector("#d-chart").style.width = (d2 / total * 100) + "%";
document.querySelector("#i-chart").style.width = (i2 / total * 100) + "%";
document.querySelector("#s-chart").style.width = (s2 / total * 100) + "%";
document.querySelector("#c-chart").style.width = (c2 / total * 100) + "%";
}
function showResults() {
document.querySelector("#d-score").innerHTML = d2;
document.querySelector("#i-score").innerHTML = i2;
document.querySelector("#s-score").innerHTML = s2;
document.querySelector("#c-score").innerHTML = c2;
document.querySelector("#scroll-down").classList.remove("hidden");
}
return {
processForm: function() {
if (getScores()) {
calculateWeightedScores();
createCharts();
showResults();
} else {
alert("Please answer all questions before calculating results.");
}
}
};
})();
document.querySelector("#submit").onclick = function() {
DiscModule.processForm();
};`
This is the HTML code:
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Triven - DISC Test</title>
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css'>
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lato:400,700'><link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- Questions-->
<div class="container"><div class="row">
<div class="page-header col-xs-12">
<h1>test</h1>
</div>
<div id="scroll-down" class="hidden">
</div>
<div class="q col-xs-12 col-sm-6 col-lg-3">
<div class="row">
<div class="col-xs-6">
<span class="badge">1</span><br><br>
Enthusiastic<br>
Daring<br>
Diplomatic<br>
Satisfied
</div>
<div class="col-xs-3 text-center">
MOST<br><br>
<input type="radio" name="q1most" value="i-most"><br>
<input type="radio" name="q1most" value="d-most"><br>
<input type="radio" name="q1most" value="c-most"><br>
<input type="radio" name="q1most" value="s-most">
</div>
<div class="col-xs-3 text-center">
LEAST<br><br>
<input type="radio" name="q1least" value="i-least"><br>
<input type="radio" name="q1least" value="d-least"><br>
<input type="radio" name="q1least" value="c-least"><br>
<input type="radio" name="q1least" value="s-least">
</div>
</div>
</div>
Solution
I think the following does what you need - if the user selects both "Most" & "Least" for a particular option in a particular question ( hard to test with only a single question ) then an alert warning the user will be displayed.
This is achieved here using a global variable (within scope of the DiscModule function ) that is initialised as an object literal and entries within as scoped as arrays. These arrays hold the "Most" / "Least" values selected per question - two the same mean the user selected an illegal pairing.
It feels like this could be refined perhaps.
var DiscModule = (function() {
var d, i, s, c, d2, i2, s2, c2;
let pairs={};
function getScores() {
d = i = s = c = 0;
var inputs = document.querySelectorAll('input[type="radio"]');
for ( var count = 0, l = inputs.length; count < l; count++ ) {
if ( inputs[count].checked ) {
/*
It is easier to work with name/value than inputs[count].name etc
and we can ignore text such as most & least as we need a unique
name for key in pairs object.
*/
let name=inputs[count].name.replace(/(most|least)/gi,'');
let value=inputs[count].value;
/*
Create an array within the pairs object to store values
of both MOST / LEAST
*/
if( !Array.isArray( pairs[ name ] ) )pairs[ name ]=[];
/*
push the letter character into array
- if there are two the same later then the user has mucked up!
*/
pairs[ name ].push( value.replace(/(most|least|-)/gi,'') )
switch(value) {
case "d-most":
d++;
break;
case "i-most":
i++;
break;
case "s-most":
s++;
break;
case "c-most":
c++;
break;
case "d-least":
d--;
break;
case "i-least":
i--;
break;
case "s-least":
s--;
break;
case "c-least":
c--;
break;
}
if( Object.keys( pairs[ name ] ).length==2 ){
if( pairs[ name ][ 0 ]==pairs[ name ] [ 1 ] ){
pairs={};
alert('\nComputer says No!\n\nYou cannot answer both "Most" & "Least" for the same option...');
return
}
}
}
}
// return here because insufficient questions posted by @OP
return true;
// checks if all questions are answered
return (d !== 0 && i !== 0 && s !== 0 && c !== 0);
}
// calculations for the test
function calculateWeightedScores() {
if (d >= 6) d2 = 7;
else if (d >= -1) d2 = 6;
else if (d >= -5) d2 = 5;
else if (d >= -9) d2 = 4;
else if (d >= -13) d2 = 3;
else if (d >= -16) d2 = 2;
else d2 = 1;
if (i >= 8) i2 = 7;
else if (i >= 5) i2 = 6;
else if (i >= 2) i2 = 5;
else if (i >= -1) i2 = 4;
else if (i >= -4) i2 = 3;
else if (i >= -8) i2 = 2;
else i2 = 1;
if (s >= 12) s2 = 7;
else if (s >= 8) s2 = 6;
else if (s >= 5) s2 = 5;
else if (s >= 1) s2 = 4;
else if (s >= -2) s2 = 3;
else if (s >= -7) s2 = 2;
else s2 = 1;
if (c >= 6) c2 = 7;
else if (c >= 3) c2 = 6;
else if (c >= -1) c2 = 5;
else if (c >= -3) c2 = 4;
else if (c >= -7) c2 = 3;
else if (c >= -11) c2 = 2;
else c2 = 1;
}
function createCharts() {
var total = 7;
document.querySelector("#d-chart").style.width = (d2 / total * 100) + "%";
document.querySelector("#i-chart").style.width = (i2 / total * 100) + "%";
document.querySelector("#s-chart").style.width = (s2 / total * 100) + "%";
document.querySelector("#c-chart").style.width = (c2 / total * 100) + "%";
}
function showResults() {
document.querySelector("#d-score").innerHTML = d2;
document.querySelector("#i-score").innerHTML = i2;
document.querySelector("#s-score").innerHTML = s2;
document.querySelector("#c-score").innerHTML = c2;
document.querySelector("#scroll-down").classList.remove("hidden");
}
return {
processForm: function() {
if (getScores()) {
calculateWeightedScores();
createCharts();
showResults();
pairs={};
} else {
alert("Please answer all questions before calculating results.");
}
}
};
})();
document.querySelector("#submit").onclick = function() {
DiscModule.processForm();
};
body {
font: 15px/1.5em Lato, sans-serif;
}
.q {
border-bottom: 1px solid #CCC;
padding-top: 1em;
padding-bottom: 1em;
}
.q:nth-of-type(odd) {
background-color: #F5F5F5;
}
.pull-left {
margin: 0 20px 0 0;
width: 50px;
}
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css'>
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Lato:400,700'>
<div class="container">
<div class="row">
<div class="page-header col-xs-12">
<h1>test</h1>
</div>
<div id="scroll-down" class="hidden"></div>
<div class="q col-xs-12 col-sm-6 col-lg-3">
<div class="row">
<div class="col-xs-6">
<span class="badge">1</span><br>
<br> Enthusiastic
<br> Daring
<br> Diplomatic
<br> Satisfied
</div>
<div class="col-xs-3 text-center">
MOST<br><br>
<input type="radio" name="q1most" value="i-most"><br>
<input type="radio" name="q1most" value="d-most"><br>
<input type="radio" name="q1most" value="c-most"><br>
<input type="radio" name="q1most" value="s-most">
</div>
<div class="col-xs-3 text-center">
LEAST<br><br>
<input type="radio" name="q1least" value="i-least"><br>
<input type="radio" name="q1least" value="d-least"><br>
<input type="radio" name="q1least" value="c-least"><br>
<input type="radio" name="q1least" value="s-least">
</div>
</div>
</div>
<!--Progress Bar-->
<div class="col-xs-12">
<br>
<p class="text-center"><button id="submit" class="btn btn-primary btn-lg">Calculate Results</button></p>
<div id="results">
<div class="pull-left"><span class="badge">D</span> (<span id="d-score"></span>)</div>
<div class="progress">
<div id="d-chart" class="progress-bar progress-bar-success" role="progressbar"></div>
</div>
<div class="pull-left"><span class="badge">I</span> (<span id="i-score"></span>)</div>
<div class="progress">
<div id="i-chart" class="progress-bar progress-bar-danger" role="progressbar"></div>
</div>
<div class="pull-left"><span class="badge">S</span> (<span id="s-score"></span>)</div>
<div class="progress">
<div id="s-chart" class="progress-bar progress-bar-info" role="progressbar"></div>
</div>
<div class="pull-left"><span class="badge">C</span> (<span id="c-score"></span>)</div>
<div class="progress">
<div id="c-chart" class="progress-bar progress-bar-warning" role="progressbar"></div>
</div>
</div>
</div>
</div>
</div>
updated version
class DiscModule {
constructor() {
this.total = 7;
this.results = {
d: 0,
i: 0,
s: 0,
c: 0
};
this.scores = {
d: 0,
i: 0,
s: 0,
c: 0
};
this.matrix = {
'd': {
'6': 7,
'-1': 6,
'-5': 5,
'-9': 4,
'-13': 3,
'-16': 2
},
'i': {
'8': 7,
'5': 6,
'2': 5,
'-1': 4,
'-4': 3,
'-8': 2
},
's': {
'12': 7,
'8': 6,
'5': 5,
'1': 4,
'-2': 3,
'-7': 2
},
'c': {
'6': 7,
'3': 6,
'-1': 5,
'-3': 4,
'-7': 3,
'-11': 2
}
};
this.pttn = /(most|least|-)/gi;
this.pairs = {};
this.errors = [];
this.warning = 'It does not make sense to select both "Most" & "Least" for the same option!';
};
clearerrors() {
document.querySelectorAll('.error').forEach(n => n.classList.remove('error'))
};
seterror(n) {
n.closest('div.row').parentNode.classList.add('error');
};
logscore(name, value) {
if (!Array.isArray(this.pairs[name])) this.pairs[name] = [];
this.pairs[name].push(value.replace(this.pttn, ''));
if (this.pairs[name].length == 2) {
if (new Set(this.pairs[name]).size == 1) {
this.errors.push(name);
return name; //effectively "true"
}
}
return false;
};
validate() {
let all = [...document.querySelectorAll('[type="radio"]')].length;
let checked = [...document.querySelectorAll('[type="radio"]:checked')].length;
return ((all / 4) == checked);
};
getscores() {
return new Promise((resolve, reject) => {
if (!this.validate()) reject({
type: 1,
message: 'Please answer all questions'
});
this.clearerrors();
document.querySelectorAll('[type="radio"]:checked').forEach(n => {
let name = n.name.replace(this.pttn, '');
let value = n.value;
if (this.logscore(name, value)) {
this.seterror(n);
}
let [chr, verb] = value.split('-');
let i = verb == 'most' ? 1 : -1;
this.scores[chr] += i;
});
if (this.errors.length > 0) reject({
type: 2,
message: this.errors.join(', ')
});
resolve(this.scores);
});
};
calculate(b) {
return new Promise((resolve, reject) => {
Object.keys(this.scores).forEach(key => {
let score = this.scores[key];
let matrix = this.matrix[key];
let keys = Object.keys(matrix);
let v = 1; // default value
keys.some(p => {
let value = parseInt(p);
if (score >= value) {
v = value;
return true;
}
});
this.results[key] = matrix[v];
})
resolve(this.results);
})
};
createcharts(b) {
return new Promise((resolve, reject) => {
Object.keys(this.results).forEach(key => {
let el = document.querySelector(`#${key}-chart`);
if (el) el.style.width = (this.results[key] / this.total * 100) + "%";
})
resolve(true)
})
};
showresults(b) {
return new Promise((resolve, reject) => {
//console.log(this);
Object.keys(this.results).forEach(key => {
let el = document.querySelector(`#${key}-score`);
if (el) el.textContent = this.results[key];
})
resolve(true)
})
};
warnuser(error) {
let type = error.type;
let msg = error.message;
let content = type == 1 ? msg : `${this.warning}\n\nPlease correct: ${msg}`;
alert(content)
};
analyse() {
this.getscores()
.then(b => this.calculate(b))
.then(b => this.createcharts(b))
.then(b => this.showresults(b))
.catch(e => this.warnuser(e))
};
};
document.querySelector('button#submit').addEventListener('click', e => {
let app = new DiscModule();
app.analyse()
})
body {
font: 15px/1.5em Lato, sans-serif;
}
body {
padding: 0;
margin: 0;
height: 100vh;
width: 100%;
}
h1 {
margin: 0.1rem auto!important;
}
.q {
display: block!important;
clear: both;
margin: 0.25rem;
border: 1px dotted grey;
padding: 0.25rem;
}
.row {
margin: 0.1rem auto;
}
[type='radio']:after {
content: attr(value);
color: black;
background: yellow;
font-family: monospace;
font-size: 1rem;
position: relative;
left: 1.5rem;
top: -0.5rem;
width: 5rem;
display: inline-block;
border-right: 2px solid black;
border-bottom: 1px solid black;
}
.container>.row {
display: flex;
flex-direction: row;
}
.container>.row>section {
flex: 1;
display: block;
margin: 0.5rem;
}
.container>.row>section>.q {
width: 100%;
margin: 0.25rem;
}
.pb {
width: 60%;
margin: auto;
float: none;
}
.error {
border: 1px dotted red;
background: rgba(255, 0, 0, 0.1)!important;
}
[data-score!=0]:after {
content: '('attr(data-score)')';
margin: 0 0 0 2rem;
color: red;
}
.q {
border-bottom: 1px solid #CCC;
padding-top: 1em;
padding-bottom: 1em;
}
.q:nth-of-type(odd) {
background-color: #F5F5F5;
}
.pull-left {
margin: 0 20px 0 0;
width: 50px;
}
<link rel='stylesheet' href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css'>
<link rel='stylesheet' href='//fonts.googleapis.com/css?family=Lato:400,700'>
<div class="container">
<div class="row">
<section>
<div class="q col-xs-12 col-sm-6 col-lg-3">
<div class="row">
<div class="col-xs-6">
<span class="badge">1</span><br>
<br> Enthusiastic
<br> Daring
<br> Diplomatic
<br> Satisfied
</div>
<div class="col-xs-3 text-center">
MOST<br><br>
<input type="radio" name="q1most" value="i-most" checked><br>
<input type="radio" name="q1most" value="d-most"><br>
<input type="radio" name="q1most" value="c-most"><br>
<input type="radio" name="q1most" value="s-most">
</div>
<div class="col-xs-3 text-center">
LEAST<br><br>
<input type="radio" name="q1least" value="i-least"><br>
<input type="radio" name="q1least" value="d-least" checked><br>
<input type="radio" name="q1least" value="c-least"><br>
<input type="radio" name="q1least" value="s-least">
</div>
</div>
</div>
<div class="q col-xs-12 col-sm-6 col-lg-3">
<div class="row">
<div class="col-xs-6">
<span class="badge">2</span><br>
<br> Intelligent
<br> Decisive
<br> Courageous
<br> Heroic
</div>
<div class="col-xs-3 text-center">MOST<br><br>
<input type="radio" name="q2most" value="i-most" checked><br>
<input type="radio" name="q2most" value="d-most"><br>
<input type="radio" name="q2most" value="c-most"><br>
<input type="radio" name="q2most" value="s-most">
</div>
<div class="col-xs-3 text-center">LEAST<br><br>
<input type="radio" name="q2least" value="i-least"><br>
<input type="radio" name="q2least" value="d-least"><br>
<input type="radio" name="q2least" value="c-least" checked><br>
<input type="radio" name="q2least" value="s-least">
</div>
</div>
</div>
<div class="q col-xs-12 col-sm-6 col-lg-3">
<div class="row">
<div class="col-xs-6">
<span class="badge">3</span><br>
<br> Charismatic
<br> Arrogant
<br> Apathetic
<br> Sociopathic
</div>
<div class="col-xs-3 text-center">MOST<br><br>
<input type="radio" name="q3most" value="i-most" checked><br>
<input type="radio" name="q3most" value="d-most"><br>
<input type="radio" name="q3most" value="c-most"><br>
<input type="radio" name="q3most" value="s-most">
</div>
<div class="col-xs-3 text-center">LEAST<br><br>
<input type="radio" name="q3least" value="i-least"><br>
<input type="radio" name="q3least" value="d-least"><br>
<input type="radio" name="q3least" value="c-least"><br>
<input type="radio" name="q3least" value="s-least" checked>
</div>
</div>
</div>
<div class="q col-xs-12 col-sm-6 col-lg-3">
<div class="row">
<div class="col-xs-6">
<span class="badge">4</span><br>
<br> Apologetic
<br> Obsequious
<br> Attentive
<br> Dominant
</div>
<div class="col-xs-3 text-center">MOST<br><br>
<input type="radio" name="q4most" value="i-most" checked><br>
<input type="radio" name="q4most" value="d-most"><br>
<input type="radio" name="q4most" value="c-most"><br>
<input type="radio" name="q4most" value="s-most">
</div>
<div class="col-xs-3 text-center">LEAST<br><br>
<input type="radio" name="q4least" value="i-least"><br>
<input type="radio" name="q4least" value="d-least" checked><br>
<input type="radio" name="q4least" value="c-least"><br>
<input type="radio" name="q4least" value="s-least">
</div>
</div>
</div>
</section>
<section>
<div class="q col-xs-12 col-sm-6 col-lg-3">
<div class="row">
<div class="col-xs-6">
<span class="badge">5</span><br>
<br> Humble
<br> Honest
<br> Creative
<br> Obedient
</div>
<div class="col-xs-3 text-center">MOST<br><br>
<input type="radio" name="q5most" value="i-most" checked><br>
<input type="radio" name="q5most" value="d-most"><br>
<input type="radio" name="q5most" value="c-most"><br>
<input type="radio" name="q5most" value="s-most">
</div>
<div class="col-xs-3 text-center">LEAST<br><br>
<input type="radio" name="q5least" value="i-least"><br>
<input type="radio" name="q5least" value="d-least" checked><br>
<input type="radio" name="q5least" value="c-least"><br>
<input type="radio" name="q5least" value="s-least">
</div>
</div>
</div>
<div class="q col-xs-12 col-sm-6 col-lg-3">
<div class="row">
<div class="col-xs-6">
<span class="badge">6</span><br>
<br> Destructive
<br> Demonic
<br> Selfish
<br> Spiteful
</div>
<div class="col-xs-3 text-center">MOST<br><br>
<input type="radio" name="q6most" value="i-most" checked><br>
<input type="radio" name="q6most" value="d-most"><br>
<input type="radio" name="q6most" value="c-most"><br>
<input type="radio" name="q6most" value="s-most">
</div>
<div class="col-xs-3 text-center">LEAST<br><br>
<input type="radio" name="q6least" value="i-least"><br>
<input type="radio" name="q6least" value="d-least" checked><br>
<input type="radio" name="q6least" value="c-least"><br>
<input type="radio" name="q6least" value="s-least">
</div>
</div>
</div>
<div class="q col-xs-12 col-sm-6 col-lg-3">
<div class="row">
<div class="col-xs-6">
<span class="badge">7</span><br>
<br> Determined
<br> Altruistic
<br> Defiant
<br> Valiant
</div>
<div class="col-xs-3 text-center">MOST<br><br>
<input type="radio" name="q7most" value="i-most" checked><br>
<input type="radio" name="q7most" value="d-most"><br>
<input type="radio" name="q7most" value="c-most"><br>
<input type="radio" name="q7most" value="s-most">
</div>
<div class="col-xs-3 text-center">LEAST<br><br>
<input type="radio" name="q7least" value="i-least"><br>
<input type="radio" name="q7least" value="d-least"><br>
<input type="radio" name="q7least" value="c-least" checked><br>
<input type="radio" name="q7least" value="s-least">
</div>
</div>
</div>
</section>
</div>
</div>
<!--Progress Bar-->
<div class="col-xs-12 pb">
<br>
<p class="text-center">
<button id="submit" class="btn btn-primary btn-lg">Calculate Results</button>
</p>
<div id="results">
<div class="pull-left">
<span class="badge">D</span>
<span id="d-score" data-score=0></span>
</div>
<div class="progress">
<div id="d-chart" class="progress-bar progress-bar-success" role="progressbar"></div>
</div>
<div class="pull-left">
<span class="badge">I</span>
<span id="i-score" data-score=0></span>
</div>
<div class="progress">
<div id="i-chart" class="progress-bar progress-bar-danger" role="progressbar"></div>
</div>
<div class="pull-left">
<span class="badge">S</span>
<span id="s-score" data-score=0></span>
</div>
<div class="progress">
<div id="s-chart" class="progress-bar progress-bar-info" role="progressbar"></div>
</div>
<div class="pull-left">
<span class="badge">C</span>
<span id="c-score" data-score=0></span>
</div>
<div class="progress">
<div id="c-chart" class="progress-bar progress-bar-warning" role="progressbar"></div>
</div>
</div>
</div>
Answered By - Professor Abronsius
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.