I would like to simply .show() a div based on a web forms radio button (user) selections.
For brevity lets take below (but note I'm looking for somewhat scaleable advice as my web form will have 7 questions and 5 answers each. And I have 5 results divs)
Note:// So, basically there will be 7 questions and 5 answers each. so I will need an array with 5 possible answer combinations via user radio button selection, ideally using the input 'value' field; so I can simply change the values of what value combos would equal what div results screen. The div results screens will just be 5 unique sets of content inside the div, that's it.
Mark-Up:
<div class="page1">
<form class="sampler">
<input type="radio" name="sex" value="male" checked>Male
<br>
<input type="radio" name="sex" value="female">Female
</form>
</div>
<div class="page2">
<form class="sampler">
<input type="radio" name="food" value="tacos" checked>Tacos
<br>
<input type="radio" name="food" value="spicynuts">Rotten Spicy Peanuts
</form>
</div>
<div id="resultsONE"><!-- one results div is display none by default sample but there would be much more content here -->
<p>Congratulations, you are NOT the father</p>
</div>
I know the below is terrible syntax; but this was the logic I was thinking about starting with on JS side. Note I will have 5 unique results #divs.
function resultsdivONE () {
if ($input value == "male" & "tacos") {
$('#resultsONE').show();
} else if () {
// do
} else {
// do
}
}
As I mentioned above; I'm looking for a method where I can simply use the SELECTED input value=""; so they can be changed somewhat easily.
Example.
if ("male" & "tacos" & "nextanswer" & "nextanswerafter") { // etc up to 7
$('#resultsONE').show();
} // first results div
May be open to php options.
Thanks for taking a look!
So basically, what is seeked is a simple form containing radio buttons and results which should match a combination of the radio-choices.According to the question, the questions should be easily maintainable and changable, without always touching a script or its initial logic. This votes for outsourcing the questions and the logic - seperate it from the DOM.
Shortly mentioned and furthermore visible in the question tags are php and ajax. Given that there might be the wish to outsource the questions completely and grab them from php by ajax. Another vote for outsourcing.
For brevity lets take below (but note I'm looking for somewhat scaleable advice as my web form will have 7 questions and 5 answers each. And I have 5 results divs)
To make it easily maintainable, the questions and answers are going to be outsourced into a json file (here JSON.js). Given this, it is also possible to retrieve it by php or any webservice and/or store those in a database. Furthermore the possibility is provided to create multiple forms with yet different questions which all use the same code.
There is a Fiddle available for it
<html>
<head>
<!-- optional styles -->
<style>
#Container{
left: 50%;
position: absolute;
text-align: center;
top: 50%;
transform: translate(-50%, -50%);
}
</style>
<script>
//This is out simple AJAX routine to not overload it by any framework.
//If you are already using jQuery, just use $.get()
;var AJAX = {
getXmlDoc: function(){return ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"))},
//u:=url, f:=callback, c:=any param to pass to callback
Get: function(u, f, c){
var tDoc = this.getXmlDoc();
tDoc.open('GET', u, true);
tDoc.onreadystatechange = function(){
if (tDoc.readyState === XMLHttpRequest.DONE && tDoc.status === 200) f(tDoc, c);
};
tDoc.send();
}
};
//This is going to be the namespace holding our functionality.
//In the end one should outsource this to a script file, yet we leave it here in the example for a better overview.
;var Quiz = {
mContainer: null, //In this container the quiz gets created in
mCurrent: null, //Stores the current displayed question
mJSON: null, //In here we are going to store the JSON result
//Handling logical errors, like missing data or json
_Error: function(m){
console.log(m)
},
//The event called on the radio change event
//e:=element
_onChange: function(e){
if (e && this.mJSON.questions[this.mCurrent]){
//We are going to those the result of this question in the JSON
this.mJSON.questions[this.mCurrent].value = e.value;
//If the question is not the last, we are going to display the next one
if (this.mCurrent < this.mJSON.questions.length - 1){
this.hideQuestions();
this.showQuestion(this.mCurrent + 1)
}
else{
//Else we are going to show the result
this.hideQuestions();
this.showResult()
}
}
else this._Error('_onChange(): Invalid parameters')
},
//The function to initialise our quiz.
//We are going to grab the json data and analyse it.
//c:=container element || document.body, l:=link || 'JSON.js'
Init: function(c, l){
this.mContainer = (c || document.body);
var tL = (l || 'JSON.js');
AJAX.Get(tL, function(r, l){
Quiz.mJSON = JSON.parse(r.response);
if (Quiz.mJSON && Quiz.mJSON.questions)
Quiz.showQuestion(0)
else
Quiz._Error('Init(): No questions found with "' + l + '"')
}, tL)
},
//Hiding the previously asked questions (remove from dom)
hideQuestions: function(){
while(this.mContainer.firstChild) this.mContainer.removeChild(this.mContainer.firstChild)
},
//Going to show the result according to the asked questions
showResult: function(){
var tValues = []; //Storing our answers
for(var i=0, j=this.mJSON.questions.length; i<j; i++)
if (this.mJSON.questions[i].value) tValues.push(this.mJSON.questions[i].value)
//Going to store the result text
var tResult = 'No match for ' + tValues.join(',');
//Looping through all requirements to get a match
for(var i=0, j=this.mJSON.answers.length; i<j; i++){
//The requirements which need to match the values
var tR = this.mJSON.answers[i].requirement;
//For this we filter all the elements which do not match the requirements
var tF = tValues.filter(function(e){return tR.indexOf(e) === -1})
//If that list is empty, all elements matched and we can stop
if (!tF || tF.length === 0){
tResult = this.mJSON.answers[i].message;
break;
}
}
//Now we are going to dislpay the result
var tH = document.createElement('h1');
tH.innerHTML = tResult;
this.mContainer.appendChild(tH)
},
//This creates and shows a question of our question array
//i:=JSON.questions array index
showQuestion: function(i){
if (i >= 0 && i<this.mJSON.questions.length){
this.mCurrent = i;
var tQ = this.mJSON.questions[i];
var tN = Object.getOwnPropertyNames(tQ)[0]; //The property name is going to become the radio group name
//We are going to create a title (h1) and multiple radios (input & label) for each question
var tF = document.createDocumentFragment();
//Creating the header
var tH = document.createElement('h1');
tH.innerHTML = tQ.label;
tF.appendChild(tH);
//Creating the questions
for(var i=0, j=tQ[tN].length; i<j; i++){
var tR = document.createElement('input');
tR.type = 'radio';
tR.value = tQ[tN][i];
tR.name = tN;
tR.onchange = function(){Quiz._onChange(this)};
tF.appendChild(tR);
var tL = document.createElement('label');
tL.for = tR.name;
tL.innerHTML = tR.value;
tF.appendChild(tL);
}
//Now we are going to assign it to the dom.
this.mContainer.appendChild(tF)
}
else{
this.mCurrent = null;
this._Error('showQuestion(' + i.toString() + '): No such question loaded')
}
}
};
</script>
</head>
<body onload = "Quiz.Init(document.querySelector('#Container'))">
<div id = 'Container'>
<!-- Container for the quiz -->
</div>
</body>
</html>
{
"questions": [
{"sex": ["male", "female"], "label": "What are you?"},
{"food": ["tacos", "spicynuts"], "label": "What do you eat?"},
{"team": ["team a", "team b", "team rocket"], "label": "Where do you belong to?"}
],
"answers": [
{"requirement": ["male", "tacos", "team a"], "message": "one has chosen male, tacos and team a"},
{"requirement": ["female", "tacos", "team a"], "message": "one has chosen female, tacos and team a"}
]
}
A small question occured to me while writing my suggestion. Given your explanation "there are seven questions and five results". Do some outcomes share results or have none?
To solve the sharing result issue, I though of two ways which I think are the most simple to input and maintain.
This solution might sound silly and too simple. Yet it is easy to maintain and manage. The obvious downfall is the lack of data integrity.
{"requirement": ["male", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"},
{"requirement": ["female", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"}
Another way is to nest requirements (array in array/object), so that one may simply list more requirements with same message. The downfall here is, that even if one never needs it, one had to structure it that way.
{
"requirement": [
["male", "tacos", "team rocket"],
["male", "spicynuts", "team rocket"],
["female", "tacos", "team rocket"],
["female", "spicynuts", "team rocket"]
],
"message": "team rocket rocks my socks!"
}
In the end I decided to let the user decide and support both methods and a combination of initial and solution number two. One can structure it like before, one can repeat answers with equal messages or one can nest requirements.
One function in the main code file
//Going to show the result according to the asked questions
showResult: function(){
var tValues = []; //Storing our answers
for(var i=0, j=this.mJSON.questions.length; i<j; i++)
if (this.mJSON.questions[i].value) tValues.push(this.mJSON.questions[i].value)
//Going to store the result text
var tResult = 'No match for ' + tValues.join(',');
//Looping through all requirements to get a match
var tBreak = false; //We use this to double break both loops
for(var i=0, j=this.mJSON.answers.length; i<j && !tBreak; i++){
//The requirements which need to match the values
var tR = this.mJSON.answers[i].requirement;
//We put simple arrays in a nested array to keep the same logic/process
var tRR = (typeof tR[0] === 'string') ? [tR] : tR;
for(var k=0, l=tRR.length; k<l && !tBreak; k++){
//For this we filter all the elements which do not match the requirements
var tF = tValues.filter(function(e){return tRR[k].indexOf(e) === -1})
//If that list is empty, all elements matched and we can stop
if (!tF || tF.length === 0){
tResult = this.mJSON.answers[i].message;
tBreak = true;
}
}
//If that list is empty, all elements matched and we can stop
if (!tF || tF.length === 0){
tResult = this.mJSON.answers[i].message;
break;
}
}
//Now we are going to dislpay the result
var tH = document.createElement('h1');
tH.innerHTML = tResult;
this.mContainer.appendChild(tH)
},
And here is the sample JSON used for testing
{
"questions": [
{"sex": ["male", "female"], "label": "What are you?"},
{"food": ["tacos", "spicynuts"], "label": "What do you eat?"},
{"team": ["team a", "team b", "team rocket"], "label": "Where do you belong to?"}
],
"answers": [
{"requirement": ["male", "tacos", "team a"], "message": "one has chosen male, tacos and team a"},
{"requirement": ["female", "tacos", "team a"], "message": "one has chosen female, tacos and team a"},
{"requirement": ["male", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"},
{"requirement": ["female", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"},
{
"requirement": [
["male", "tacos", "team rocket"],
["male", "spicynuts", "team rocket"],
["female", "tacos", "team rocket"],
["female", "spicynuts", "team rocket"]
],
"message": "team rocket rocks my socks!"
}
]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With