Making a quiz app, stuck on a function - javascript

I'm making a simple quiz app. But I'm stuck on ordering the functions.
Here is the code
// questions set
var qtnsSet = [
// format: [question, [comma, separated, options], index of correct ans. eg. 1]
["What is the full form of IP?", ["Internet Provider", "Internet Port", "Internet Protocol"], 2],
["Who is the founder of Microsoft?", ["Bill Gates", "Steve Jobs", "Steve Wozniak"], 0],
["Full name of IBM?", ["Internet Business Machine", "International Business Machine", "Indian Business Machine"], 1]
]
// init vars
var qtnNo = 0,
score = 0;
// define elements
var qtnContainer = $("qtn-container"),
optnsContainer = $("optns-container"),
submitBtn = $("submit-btn");
function $(id) { // Shortcut for document.getElementById
return document.getElementById(id);
}
function askQtn() { // ask question
var optns = qtnsSet[qtnNo][1], // options array
optnsHtml = "";
for (var optnNo = 0; optnNo < optns.length; optnNo++) {
optnsHtml += createOptnHtml(optnNo, optns[optnNo]);
}
qtnContainer.textContent = qtnsSet[qtnNo][0]; // question
optnsContainer.innerHTML = optnsHtml; // options
}
function createOptnHtml(optnNo, optn) { // create html elements for options
// eg. <li><input type='radio' name='optn' value='Option' id='optn-0'>
// <label for='optn-0'>Option</label></li>
return "<li><h3><input type='radio' name='optn' value='" + optn + "' id='optn-" + optnNo + "'>" +
" <label for='optn-" + optnNo + "'>" + optn + "</label></h3></li>";
}
function getGivenAns() { // get the answer given by user
var optns = document.getElementsByName("optn");
for (var optnNo = 0; optnNo < optns.length; optnNo++) {
if (optns[optnNo].checked) {
return optnNo; // index of the chosen answer
}
}
}
function checkAns() { // check if user's right or not
if (getGivenAns() == qtnsSet[qtnNo][2]) {
score += 6; // 6 points for right answer
}
}
function submitAns() {
if (qtnNo <= qtnsSet.length) {
if (getGivenAns()) {
checkAns();
qtnNo++;
askQtn();
} else {
alert("Please choose an answer.");
};
} else {
alert("Score: " + score);
};
}
window.addEventListener("load", askQtn, false);
submitBtn.addEventListener("click", submitAns, false);
I'm unable to configure the submitAns() function so that every thing works correctly.
How can I order the functions inside submitAns()?

getGivenAns()
Returns the index of the options, which can be 0 if the first option is selected which would evaluate to false here:
if (getGivenAns()) {
so just return true if an option is checked.
Also
if (qtnNo <= qtnsSet.length) {
Will be true after the last question it should just be
if (qtnNo < qtnsSet.length) {

Related

Problem in executing the complete javascript

The program is not running and just showing blank window when opened in browser. Please help me found the issue with the code why it is not executing You need to create a program that will display flight information to a person. The program will continue to provide
information to the user until they indicate that they are no longer interested in searching (they will enter Q or X to stop).
The user will be prompted to enter a city to search for and you will look for any flight that starts in this city and display
the information associated with that flight.
//declare the arrays
startCity = ["Atlanta", " Cleveland", " Indianapolis", "Louisville"];
endcity = ["Cleveland", "Indianapolis", "Louisville ", "Atlanta"];
flightNumber = [RE103, RE305, RE307, RE309];
pricePerPerson = [110, 75, 90, 120];
//window onload method
window.onload = (function() {
//call function to prompt user
processPromtExecution();
//prmpt user to ask input
function processPromtExecution() {
//ask user to privide imput
var inputString = prompt("Looking for a flight? Enter the title or X to quit", "");
//check user input and if inpt is Q/q/X/x the quti with message
if (inputString == "Q" || inputString == "X" || inputString == "x" || inputString == "q") {
$("#idSpan").append("<hr /> <br />");
$("#idSpan").append("Thank you for using our flights system.");
} else {
//else search the input
for (var i = 0; i < startCity.length; i++) {
//chck input strin is part of array of book titles element or not
if (startCity[i].toLowerCase().indexOf(inputString.toLowerCase()) >= 0) {
//if matches then fetch index of other arrays
var startCity = startCity[i];
var endCity = endCity[i];
var flightNumber = flightNumber[i];
var pricePerPerson = pricePerPerson[i];
//print the message below
document.getElementById("idSpan").style.display = "block";
$("#idSpan").append("<hr />");
//set the values
$("#idSpan").append("flight Information: <br />");
$("#idSpan").append("starta: " + startCity + "<br />");
$("#idSpan").append("endCity: " + endCity + "<br />");
$("#idSpan").append("Number: " + flightNumber + "<br />");
$("#idSpan").append("Cost: " + pricePerPerson + "<br />");
//ask again
processPromtExecution();
}
}
}
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<span id="idSpan" style="display:none;">Welcome to the Javascript flightS</span>
</body>
</html>
Looks like you forgot the quote in your array with string and numbers combined in the following line:
flightNumber = [RE103, RE305, RE307, RE309];
Shouldn't it look like this:
flightNumber = ["RE103", "RE305", "RE307", "RE309"];
Consider the following.
/*
//declare the arrays
startCity = ["Atlanta", " Cleveland", " Indianapolis", "Louisville"];
endcity = ["Cleveland", "Indianapolis", "Louisville ", "Atlanta"];
flightNumber = ["RE103", "RE305", "RE307", "RE309"];
pricePerPerson = [110, 75, 90, 120];
*/
// Prepare data
var flights = [{
flightNumber: "RE103",
city: {
start: "Atlanta",
finish: "Cleveland"
},
pricePerPerson: 110
}, {
flightNumber: "RE305",
city: {
start: "Cleveland",
finish: "Indianapolis"
},
pricePerPerson: 75
}, {
flightNumber: "RE307",
city: {
start: "Indianapolis",
finish: "Louisville"
},
pricePerPerson: 90
}, {
flightNumber: "RE309",
city: {
start: "Louisville",
finish: "Atlanta"
},
pricePerPerson: 120
}];
$(function() {
// Define Functions
function getFlightDataByNumber(flightNumber, flightData) {
var results = false;
$.each(flightData, function(index, flight) {
if (flight.flightNumber.toLowerCase() == flightNumber.toLowerCase()) {
results = flight;
}
});
return results;
}
function getFlightDataByStart(cityName, flightData) {
var results = false;
$.each(flightData, function(index, flight) {
if (flight.city.start.toLowerCase() == cityName.toLowerCase()) {
results = flight;
}
});
return results;
}
function promptForFlight() {
var inputString = prompt("Looking for a flight? Enter the title or X to quit", "");
if (inputString == "Q" || inputString == "X" || inputString == "x" || inputString == "q") {
$("#idSpan").append("<hr /> <br />");
$("#idSpan").append("Thank you for using our flights system.");
} else {
var myFlight = getFlightDataByStart(inputString, flights);
if (myFlight !== false) {
$("#idSpan").show();
$("<ul>", {
class: "flightData"
}).insertAfter("#idSpan");
$("<li>").html("<label>Flight Information:</label>").appendTo(".flightData");
$("<li>").html("<label class='fixed'>Departs:</label>" + myFlight.city.start).appendTo(".flightData");
$("<li>").html("<label class='fixed'>Arrives:</label>" + myFlight.city.finish).appendTo(".flightData");
$("<li>").html("<label class='fixed'>Number:</label>" + myFlight.flightNumber).appendTo(".flightData");
$("<li>").html("<label class='fixed'>Cost:</label>$" + myFlight.pricePerPerson.toFixed(2)).appendTo(".flightData");
}
}
}
// Run Code
promptForFlight();
});
/*
//window onload method
window.onload = (function() {
//call function to prompt user
processPromtExecution();
//prmpt user to ask input
function processPromtExecution() {
//ask user to privide imput
var inputString = prompt("Looking for a flight? Enter the title or X to quit", "");
//check user input and if inpt is Q/q/X/x the quti with message
if (inputString == "Q" || inputString == "X" || inputString == "x" || inputString == "q") {
$("#idSpan").append("<hr /> <br />");
$("#idSpan").append("Thank you for using our flights system.");
} else {
//else search the input
for (var i = 0; i < startCity.length; i++) {
//chck input strin is part of array of book titles element or not
if (startCity[i].toLowerCase().indexOf(inputString.toLowerCase()) >= 0) {
//if matches then fetch index of other arrays
var startCity = startCity[i];
var endCity = endCity[i];
var flightNumber = flightNumber[i];
var pricePerPerson = pricePerPerson[i];
//print the message below
document.getElementById("idSpan").style.display = "block";
$("#idSpan").append("<hr />");
//set the values
$("#idSpan").append("flight Information: <br />");
$("#idSpan").append("starta: " + startCity + "<br />");
$("#idSpan").append("endCity: " + endCity + "<br />");
$("#idSpan").append("Number: " + flightNumber + "<br />");
$("#idSpan").append("Cost: " + pricePerPerson + "<br />");
//ask again
processPromtExecution();
}
}
}
}
});
*/
.flightData {
margin: 0;
padding: 0;
list-style: none;
}
.flightData li label {
font-weight: bold;
display: inline-block;
}
.flightData li label.fixed {
width: 120px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span id="idSpan" style="display:none;">Welcome to the Javascript flightS</span>
Instead of using multiple unique Arrays, you may want to use an Array of Objects. This will help create a relationship between the various elements. Once you have identified the one object you need, you can easily access all the other related details.
Based on your code, you are asking the User to enter a City name, yet this is not explained well in your Prompt. You should consider clarifying the prompt better or using another Input method.
Once we have the User input, we can use the function to seek out the proper object, if we do not find it, false is returned. You have no feedback to the User if the Flight cannot be found. You might consider that scenario further.

How do I display a function using setTimeout in JavaScript?

I have made a quiz with JavaScript and want that when the timer is up, it should not let you attempt the quiz anymore and go to the last page which displays the score. The score is displayed by calling displayResult. I have one HTML file and one JS file. When I use setTimeout, even after the time is up, it doesn’t show the score. I think the function doesn’t get called. I have tried using setInterval instead of setTimeout but still it doesn't work. Can someone tell me what I am doing wrong?
Whole code here.
//timer code in quiz.js
const startingMinutes = 1
let time = startingMinutes * 60
const countdownEl = document.getElementById('countdown')
var vri = setInterval(upd, 1000)
function upd() {
const minutes = Math.floor(time / 60)
let seconds = time % 60
seconds = seconds < 10 ? '0' + seconds : seconds
countdownEl.innerHTML = minutes + ":" + seconds
time--
time = time < 0 ? 0 : time
if (time == 0) {
clearInterval(vri);
}
setTimeout(displayResult, 1000);
}
The function gets called you can easily check this by inserting a console.log() inside the function.
When you would like to display the results on the same page then first clear the body and append your new created element on the body.
There is still a bug that your selected elements will always be empty but I just answer your question here "How you display it."
For debugging purposes I set the timer to 6 seconds instead of 60.
(function() {
var allQuestions = [{
question: "The tree sends downroots from its branches to the soil is know as:",
options: ["Oak", "Pine", "Banyan", "Palm"],
answer: 2
}, {
question: "Electric bulb filament is made of",
options: ["Copper", "Aluminum", "lead", "Tungsten"],
answer: 3
}, {
question: "Non Metal that remains liquid at room temprature is",
options: ["Phophorous", "Bromine", "Clorine", "Helium"],
answer: 1
}, {
question: "Which of the following is used in Pencils ?",
options: ["Graphite", "Silicon", "Charcoal", "Phosphorous"],
answer: 0
}, {
question: "Chemical formula of water ?",
options: ["NaA1O2", "H2O", "Al2O3", "CaSiO3"],
answer: 1
}, {
question: "The gas filled in electric bulb is ?",
options: ["Nitrogen", "Hydrogen", "Carbon Dioxide", "Oxygen"],
answer: 0
}, {
question: "Whashing soda is the comman name for",
options: ["Sodium Carbonate", "Calcium Bicarbonate", "Sodium Bicarbonate", "Calcium Carbonate"],
answer: 0
}, {
question: "Which gas is not known as green house gas ?",
options: ["Methane", "Nitrous oxide", "Carbon Dioxide", "Hydrogen"],
answer: 3
}, {
question: "The hardest substance availabe on earth is",
options: ["Gold", "Iron", "Diamond", "Platinum"],
answer: 2
}, {
question: "Used as a lubricant",
options: ["Graphite", "Silica", "Iron Oxide", "Diamond"],
answer: 0
}];
var quesCounter = 0;
var selectOptions = [];
var quizSpace = $('#quiz');
nextQuestion();
$('#next').click(function() {
chooseOption();
if (isNaN(selectOptions[quesCounter])) {
alert('Please select an option !');
} else {
quesCounter += 5;
nextQuestion();
}
});
$('#prev').click(function() {
chooseOption();
quesCounter -= 5;
nextQuestion();
});
function createElement(index) {
var element = $('<div>', {
id: 'question'
});
var header = $('<h2>Question No. ' + (index + 1) + ' :</h2>');
element.append(header);
var question = $('<p>').append(allQuestions[index].question);
element.append(question);
var radio = radioButtons(index);
element.append(radio);
var question1 = $('<p>').append(allQuestions[index + 1].question);
element.append(question1);
var radio1 = radioButtons1(index + 1);
element.append(radio1);
var question2 = $('<p>').append(allQuestions[index + 2].question);
element.append(question2);
var radio2 = radioButtons2(index + 2);
element.append(radio2);
var question3 = $('<p>').append(allQuestions[index + 3].question);
element.append(question3);
var radio3 = radioButtons3(index + 3);
element.append(radio3);
var question4 = $('<p>').append(allQuestions[index + 4].question);
element.append(question4);
var radio4 = radioButtons4(index + 4);
element.append(radio4);
return element;
}
function radioButtons(index) {
var radioItems = $('<ul>');
var item;
var input = '';
for (var i = 0; i < allQuestions[index].options.length; i++) {
item = $('<li>');
input = '<input type="radio" name="answer" value=' + i + ' />';
input += allQuestions[index].options[i];
item.append(input);
radioItems.append(item);
}
return radioItems;
}
function radioButtons1(index) {
var radioItems1 = $('<ul>');
var item1;
var input1 = '';
for (var i = 0; i < allQuestions[index].options.length; i++) {
item1 = $('<li>');
input1 = '<input type="radio" name="answer1" value=' + i + ' />';
input1 += allQuestions[index].options[i];
item1.append(input1);
radioItems1.append(item1);
}
return radioItems1;
}
function radioButtons2(index) {
var radioItems2 = $('<ul>');
var item2;
var input2 = '';
for (var i = 0; i < allQuestions[index].options.length; i++) {
item2 = $('<li>');
input2 = '<input type="radio" name="answer2" value=' + i + ' />';
input2 += allQuestions[index].options[i];
item2.append(input2);
radioItems2.append(item2);
}
return radioItems2;
}
function radioButtons3(index) {
var radioItems3 = $('<ul>');
var item3;
var input3 = '';
for (var i = 0; i < allQuestions[index].options.length; i++) {
item3 = $('<li>');
input3 = '<input type="radio" name="answer3" value=' + i + ' />';
input3 += allQuestions[index].options[i];
item3.append(input3);
radioItems3.append(item3);
}
return radioItems3;
}
function radioButtons4(index) {
var radioItems4 = $('<ul>');
var item4;
var input4 = '';
for (var i = 0; i < allQuestions[index].options.length; i++) {
item4 = $('<li>');
input4 = '<input type="radio" name="answer4" value=' + i + ' />';
input4 += allQuestions[index].options[i];
item4.append(input4);
radioItems4.append(item4);
}
return radioItems4;
}
function chooseOption() {
selectOptions[quesCounter] = +$('input[name="answer"]:checked').val();
selectOptions[quesCounter + 1] = +$('input[name="answer1"]:checked').val();
selectOptions[quesCounter + 2] = +$('input[name="answer2"]:checked').val();
selectOptions[quesCounter + 3] = +$('input[name="answer3"]:checked').val();
selectOptions[quesCounter + 4] = +$('input[name="answer4"]:checked').val();
}
function nextQuestion() {
quizSpace.fadeOut(function() {
$('#question').remove();
if (quesCounter < allQuestions.length) {
var nextQuestion = createElement(quesCounter);
quizSpace.append(nextQuestion).fadeIn();
if (!(isNaN(selectOptions[quesCounter, quesCounter + 1, quesCounter + 2, quesCounter + 3, quesCounter + 4]))) {
$('input[value=' + selectOptions[quesCounter] + ']').prop('checked', true);
$('input[value=' + selectOptions[quesCounter + 1] + ']').prop('checked', true);
$('input[value=' + selectOptions[quesCounter + 2] + ']').prop('checked', true);
$('input[value=' + selectOptions[quesCounter + 3] + ']').prop('checked', true);
$('input[value=' + selectOptions[quesCounter + 4] + ']').prop('checked', true);
}
if (quesCounter === 1) {
$('#prev').show();
} else if (quesCounter === 0) {
$('#prev').hide();
$('#next').show();
}
} else {
var scoreRslt = displayResult();
quizSpace.append(scoreRslt).fadeIn();
$('#next').hide();
$('#prev').hide();
}
});
}
const startingMinutes = 0.1;
let time = startingMinutes * 60
const countdownEl = document.getElementById('countdown')
var vri = setInterval(upd, 1000)
function upd() {
const minutes = Math.floor(time / 60)
let seconds = time % 60
seconds = seconds < 10 ? '0' + seconds : seconds
countdownEl.innerHTML = minutes + ":" + seconds
time--
time = time < 0 ? 0 : time
console.log(time);
if (time === 0) {
clearInterval(vri);
setTimeout(displayResult, 1000);
}
}
function displayResult() {
console.log(selectOptions);
var correct = 0;
console.log(selectOptions);
for (var i = 0; i < selectOptions.length; i++) {
if (selectOptions[i] === allQuestions[i].answer) {
correct++;
}
}
document.body.innerHTML = "";
let score = document.createElement("p");
score.id = 'question';
if (correct === 0 && correct <= 5) {
let otherText = document.createTextNode("YOUR IQ SCORES LIES IN THE RANGE OF 70 and 79 WHICH IS CLASSIFIED AS BORDERLINE");
let img = document.createElement("img");
img.src = "img9b.png"
score.append(otherText)
score.append(img);
} else {
let tex = document.createTextNode("The Result is: " + correct);
score.appendChild(tex);
}
document.body.appendChild(score);
}
})();
<html>
<head>
<title>Make Quiz Website</title>
<link rel="stylesheet" href="quiz.css">
<link href="https://fonts.googleapis.com/css?family=Josefin+Sans" rel="stylesheet">
</head>
<body>
<div id="container">
<h1>Quiz Website Using JavaScript</h1>
<br/>
<div id="quiz"></div>
<p id="countdown">30:00</p>
</h1>
<div class="button" id="next">Next</div>
<div class="button" id="prev">Prev</div>
</div>
<script src="https://code.jquery.com/jquery-3.4.0.min.js"></script>
<script src="quiz.js"></script>
</body>
</html>

Calculation does not return the correct value

can anyone tell me what is the error on this javascript code?
Program: http://utilizaweb.com.br/aposentadorianovo/
function calcula(){
var fieldsContainer=document.getElementsByClassName("trabalho")[0].
getElementsByClassName("row"),
i,
jobFields=[],
len,
newAge=0,
selfGender=document.aposentadoria.sexo.value,
workedDays=0,
workedMonthies=0,
workedYears=0;
len=fieldsContainer.length;
for(i=0;len>i;i++){
jobFields[i]={
admissionDate:new Date(fieldsContainer[i].getElementsByClassName("admissao-area")[0].children[1].value),//data de admissão,
ageRule:fieldsContainer[i].getElementsByClassName("regra-area")[0].children[0].value,//regra
demissionDate:new Date(fieldsContainer[i].getElementsByClassName("demissao-area")[0].children[1].value),//data de demissão
jobBusiness:fieldsContainer[i].getElementsByClassName("empresa-area")[0].children[1].value//empresa do trabalho
};
if (jobFields[i].demissionDate > jobFields[i].admissionDate) {
jobFields[i].workedYears=jobFields[i].demissionDate.getFullYear() - jobFields[i].admissionDate.getFullYear();
jobFields[i].workedMonthies=jobFields[i].demissionDate.getMonth() - jobFields[i].admissionDate.getMonth();
jobFields[i].workedDays=jobFields[i].demissionDate.getDate() - jobFields[i].admissionDate.getDate();
alert(jobFields[i].workedYears)
} else {
alert("A data de admissão deve ser anterior à data de demissão.");
throw new Error("Conversor :: Admission date must be older than demission date.")
}
}
var fieldsRule=[];
len=jobFields.length;
for(i=0;len>i;i++){
fieldsRule[i]=jobFields[i].ageRule
}
var calculateFields=[],
higherRule=Math.max.apply(fieldsRule)
len=jobFields.length;
for(i=0;len>i;i++){
if(fieldsRule[i]===higherRule){
calculateFields[i]=i
}
}
var ageMultiplyBy,
missingYears,
jobYearsEnd;
len=calculateFields.length;
if (selfGender === "M") {
for(i=0;len>i;i++){
ageMultiplyBy=
jobFields[calculateFields[i]].ageRule==="25"?1.40:
jobFields[calculateFields[i]].ageRule==="20"?1.75:
jobFields[calculateFields[i]].ageRule==="15"?2.33:
1.75;
newAge=jobFields[calculateFields[i]].workedYears*ageMultiplyBy;
missingYears=newAge - 35
}
} else {
for(i=0;len>i;i++){
ageMultiplyBy=
jobFields[calculateFields[i]].ageRule==="25"?1.20:
jobFields[calculateFields[i]].ageRule==="20"?1.50:
jobFields[calculateFields[i]].ageRule==="15"?2:
1.20;
newAge=jobFields[calculateFields[i]].workedYears*ageMultiplyBy;
missingYears=newAge - 30
}
}
alert(missingYears)
if (missingYears < 0) {
jobYearsEnd=missingYears * -1;
}
document.getElementById("anosTrabalhados").innerHTML = workedYears+ " anos";
document.getElementById("result").innerHTML = "<img src='./img/aviso.png'>" +"Você trabalhou " +workedYears+ " anos, " +workedMonthies+ " meses e " +workedDays+ " dias"+ "<br />" +"Faltam " +jobYearsEnd+ " anos para se aposentar"
}
[IF WASN'T WELL EXPLAINED, PLEASE TELL ME. I DONT SPEAK ENGLISH SO WELL]
I need get the value of the admissionDate and of the demissionDate and subtract of each line, including those added by the user. Then, I need get the biggest values of rules are equal, and add up the time worked in each one. Then, the program takes the time worked added up and multiply by the value of each rule and subtract of 35 in case of male and of 30 in case of female. And then displays the value calculated last (minus 30 or 35).
Where the code is wrong?
Look the code by View Source
I did what I could with this one as there are several challenges and a couple of points where I am not 100 percent sure your intent. I believe you can work from here. Date stuff is hard when you work with multiple related dates. What if the boundary crosses daylight savings time etc. To assist with that I used a date library, feel free to get another or use it, I pasted it into the fiddle code; use it or get another that does that stuff rather than re-invent one. I did not use it extensively.
Here is a saved fiddle to test/try it out: (see the bottom for the good parts) https://jsfiddle.net/MarkSchultheiss/1ttmecoe/
Link the the date library: http://slingfive.com/pages/code/jsDate/jsDate.html
Explanation:
First off, your undisclosed code replicates an ID and those MUST be unique, and when you use that it is in error. I fixed that by using jQuery .clone() I also put a method to add/remove rows (all but last one) from your list) which was lacking on your page.
Code snip:
document.getElementById("anosTrabalhados").innerHTML
I will show you how to fix that (see the markup and .clone())
You have some rather complex selectors which can be simplified by the use of classes.
Code snip:
jobFields[i]={
admissionDate:new Date(fieldsContainer[i].getElementsByClassName("admissao-area")[0].children[1].value),//data de admissão,
revised:
var thisRow = fieldsContainer[i];
jobFields[i] = {
admissionDate: new Date(thisRow.getElementsByClassName("dataAdmissao")[0].value),
Checking/validation of dates right in the middle of a loop, perhaps you might check those before you loop? I left that for now as it was.
Code snip:
if (jobFields[i].demissionDate > jobFields[i].admissionDate) {
This appears to be a syntax issue here:
higherRule=Math.max.apply(fieldsRule) //old
higherRule=Math.max.apply(null, fieldsRule); //repaired
ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max
Remove constants from code and put them in an object:
Code snip:
var calcVals = {
rules: {
male: {
sex: "M",
defaultRate: 1.75,
ageVar: 35,
ageRules: [{
age: "25",
val: 1.40
}, {
age: "20",
val: 1.75
}, {
age: "15",
val: 2.33
}]
},
female: {
sex: "M",
defaultRate: 1.50,
ageVar: 30,
ageRules: [{
age: "25",
val: 1.20
}, {
age: "20",
val: 1.50
}, {
age: "15",
val: 2.00
}]
}
}
};
then use it later: (this gets rid of the duplicate hard coded conditional making it simpler and more maintainable)
calcT = (selfGender === "M") ? calcT = calcVals.rules.male : calcT = calcVals.rules.female;
ageMultiplyBy = calcT.defaultRate;
for (i = 0; len > i; i++) {
for (var j = 0; j < calcT.ageRules.length; j++) {
if (jobFields[calculateFields[i]].ageRule === calcT.ageRules[j].age) {
ageMultiplyBy = calcT.ageRules[j].val;
break;
}
}
...more code
Assignment of a string to an array
Code snip:
fieldsRule[i]=jobFields[i].ageRule
This changes this comparison: (see the next code segment as well)
if(fieldsRule[i]===higherRule){
The fieldsRule[i] is a string and higherRule is a numeric (see the Math.max.apply above)
You set the iteration variable len based on jobFields but access the fieldsRule[i] which MIGHT be undefined. Did you mean to push to the array rather than assign to it? I ask because later on you use len=calculateFields.length; as an iterate value. Note that all the fieldsRule[i] might not be evaluated if the lengths differ on the arrays OR it might have an undefined value. (note that this is where your desired functionality becomes less clear)
len=jobFields.length;
for(i=0;len>i;i++){
if(fieldsRule[i]===higherRule){
calculateFields[i]=i
}
}
See this later down: newAge=jobFields[calculateFields[i]].workedYears*ageMultiplyBy; where calculateFields[i] might be undefined.
Revised markup:
<form class="form-calculadora" name="aposentadoria">
<fieldset class="sexo">
<legend>Sexo</legend>
<select id="sexo" class="text-area">
<option value="M">Masculino</option>
<option value="F">Feminino</option>
</select>
</fieldset>
<fieldset class="trabalho">
<div class="row p_scents">
<div class="empresa-area">
<p class="title">Empresa</p>
<input type="text" class="text-area empresa" placeholder="Empresa: ">
</div>
<div class="regra-area">
<p class="title">Regra</p>
<select class="text-area regra">
<option value="25">25 anos</option>
<option value="20">20 anos</option>
<option value="15">15 anos</option>
</select>
</div>
<div class="admissao-area">
<p class="title">Admissão</p>
<input type="date" class="text-area dataAdmissao" placeholder="Admissão: " />
</div>
<div class="demissao-area">
<p class="title">Demissão</p>
<input type="date" class="text-area dataDemissao" placeholder="Demissão: " />
</div>
<div class="anos-area">
<p class="anosTrabalhados">0 anos</p>
</div>
<button class="removerow">
Remove Row
</button>
</div>
</fieldset>
<p class="add-empresa"><i class="fa fa-user-plus"></i> Adicionar Empresa</p>
<p id="result">Você trabalhou 0 anos, 0 meses e 0 dias
<br/>Faltam undefined anos para se aposentar</p>
<input type="button" value="Calcular" class="btn" id="calcular" />
</form>
Revised code:
var calcVals = {
rules: {
male: {
sex: "M",
defaultRate: 1.75,
ageVar: 35,
ageRules: [{
age: "25",
val: 1.40
}, {
age: "20",
val: 1.75
}, {
age: "15",
val: 2.33
}]
},
female: {
sex: "M",
defaultRate: 1.50,
ageVar: 30,
ageRules: [{
age: "25",
val: 1.20
}, {
age: "20",
val: 1.50
}, {
age: "15",
val: 2.00
}]
}
}
};
function calcula() {
var rows = $('.row');
var fieldsContainer = document.getElementsByClassName("trabalho")[0].
getElementsByClassName("row"),
i,
jobFields = [],
len,
newAge = 0,
selfGender = document.aposentadoria.sexo.value,
workedDays = 0,
workedMonthies = 0,
workedYears = 0;
var fieldsRule = [];
var calculateFields = [],
len = fieldsContainer.length;
for (i = 0; i < len; i++) {
var thisRow = fieldsContainer[i];
jobFields[i] = {
admissionDate: new Date(thisRow.getElementsByClassName("dataAdmissao")[0].value),
demissionDate: new Date(thisRow.getElementsByClassName("dataDemissao")[0].value),
ageRule: thisRow.getElementsByClassName("regra")[0].value,
jobBusiness: thisRow.getElementsByClassName("empresa")[0].value
};
// console.dir(jobFields);
if (jobFields[i].demissionDate > jobFields[i].admissionDate) {
jobFields[i].workedYears = Date.DateDiff('yyyy', jobFields[i].admissionDate, jobFields[i].demissionDate);
// get months after remove years
jobFields[i].workedMonthies = Date.DateDiff('m', jobFields[i].admissionDate, jobFields[i].demissionDate) - (jobFields[i].workedYears * 12);
// console.log('days:' + Date.DateDiff('d', jobFields[i].admissionDate, jobFields[i].demissionDate) );
// get days worked after remove years/months
var adate = new Date(jobFields[i].demissionDate);
adate = new Date(adate.setFullYear(jobFields[i].demissionDate.getFullYear() - jobFields[i].workedYears));
adate = new Date(adate.setMonth((adate.getMonth()) - jobFields[i].workedMonthies));
jobFields[i].workedDays = Date.DateDiff('d', jobFields[i].admissionDate, adate); //- (new Date(jobFields[i].admissionDate) - new Date(jobFields[i].demissionDate));
// console.log('worked' + i + ":" + jobFields[i].workedYears);
} else {
alert("A data de admissão deve ser anterior à data de demissão. not less");
// throw new Error("Conversor :: Admission date must be older than demission date.")
}
}
len = jobFields.length;
for (i = 0; len > i; i++) {
fieldsRule[i] = +jobFields[i].ageRule;
}
var higherRule = Math.max.apply(null, fieldsRule);
console.log("higherRule:" + higherRule + " fLen:" + fieldsRule.length);
len = jobFields.length;
console.dir({
"jobf": jobFields
});
//console.dir(fieldsRule);
for (i = 0; i < len; i++) {
if (fieldsRule[i] === higherRule) {
calculateFields[i] = i;
}
}
console.dir({
"calcf": calculateFields
});
var ageMultiplyBy,
missingYears,
jobYearsEnd;
console.dir(fieldsRule);
len = calculateFields.length;
var calcT = {};
calcT = (selfGender === "M") ? calcT = calcVals.rules.male : calcT = calcVals.rules.female;
ageMultiplyBy = calcT.defaultRate;
for (i = 0; len > i; i++) {
for (var j = 0; j < calcT.ageRules.length; j++) {
if (jobFields[calculateFields[i]].ageRule === calcT.ageRules[j].age) {
ageMultiplyBy = calcT.ageRules[j].val;
break;
}
}
newAge = jobFields[calculateFields[i]].workedYears * ageMultiplyBy;
missingYears = newAge - calcT.ageVar;
}
console.log('mys:' + missingYears);
if (missingYears < 0) {
jobYearsEnd = (+missingYears) * -1;
}
len = jobFields.length;
for (i = 0; i < len; i++) {
workedYears = workedYears + jobFields[i].workedYears;
workedMonthies = workedMonthies + jobFields[i].workedMonthies;
workedDays = workedDays + jobFields[i].workedDays;;
}
//invalid id cannot be dupe document.getElementById("anosTrabalhados").innerHTML = workedYears + " anos";
for (var m = 0; m < rows.length; m++) {
console.log('wy:' + workedYears);
$('.row').eq(m).find('.anosTrabalhados').text(workedYears + " anos");
}
// document.getElementById("anosTrabalhados").innerHTML = workedYears + " anos";
document.getElementById("result").innerHTML = "<img src='./img/aviso.png'>" + "Você trabalhou " + workedYears + " anos, " + workedMonthies + " meses e " + workedDays + " dias" + "<br />" + "Faltam " + jobYearsEnd + " anos para se aposentar"
}
$(function() {
// set defaults for testing
makedefaults(0);
$('#calcular').on('click', function() {
calcula();
});
// add a row
$('#addScnt').on('click', function(e) {
var rowContainer = $('.trabalho');
var rows = rowContainer.find('.row');
var newRow = rows.eq(0).clone(true);
rowContainer.append(newRow);
e.preventDefault();
return false;
});
// remove any row but last one
$('.trabalho').on('click', '.removerow', function(e) {
var rowsCount = $('.trabalho').find('.row').length;
if (rowsCount > 1) {
$(this).parents('.row').remove();
}
e.preventDefault();
return false;
});
});

Repopulating objects with a click

I'm attempting to repopulate my radio buttons with the next question that is stored in my array. I'm unsure of how to remove the current question and repopulate the radio buttons with the next question.
var questionsArray = [];
//Create counters for both correct answers and current question
var correctAnswers = 0;
var currentQuestion = 0;
//Contructor Function to create questions
function Question (question, choices, answer){
this.question = question;
this.choices = choices;
this.answer = answer;
}
//Question Creations
questionsArray.push(new Question(...
To append the questions to my radio buttons I've used this code:
$('.q_question').append(questionsArray[0]['question']);
//In order to be able to check what radio is click you have to change to value of the radio buttons to the correct answer.
$('.btn1').after(questionsArray[0]['choices'][0]);
$('.btn1').val(questionsArray[0]['choices'][0]);
$('.btn2').after(questionsArray[0]['choices'][1]);
$('.btn2').val(questionsArray[0]['choices'][1]);
$('.btn3').after(questionsArray[0]['choices'][2]);
$('.btn3').val(questionsArray[0]['choices'][2]);
$('.btn4').after(questionsArray[0]['choices'][3]);
$('.btn4').val(questionsArray[0]['choices'][3]);
To check the answers I've got with:
$('#submit').on('click', function(){
currentQuestion ++;
var answer = $('input[name="1"]:checked').val(); //By creating the answer variable we are able to store which radio button value is submitted.
if(answer == questionsArray[0]['answer']){
correctAnswers ++;
$('.jumbotron').append(answer + "?<br><br> That's correct! You have " + correctAnswers + " out of 10 correct!");
} else {
$('.jumbotron').append(answer+ "? <br><br> Oh dear, that's so so wrong! You have " + correctAnswers + " out of 10 correct");
}
return false;
});
I'm totally stuck now.
Here's an example of something you could do: Fiddle
Create a function to populate the question and options. Add <span> or <label> elements and change the html in them instead of just using .after().
function populateQuestion(index) {
$('.q_question').html(questionsArray[index]['question']);
for (var i = 0; i < 4; i++) {
$('.jumbotron').html('');
$('.btn' + (i + 1)).val(questionsArray[index]['choices'][i]).prop('checked', false);
$('.label' + (i + 1)).html(questionsArray[index]['choices'][i]);
}
}
Add an event listener for the "Continue" button that runs the function with the correct (updated) index:
$('.continue').on('click', function() {
populateQuestion(++currentQuestion);
});
Just be sure to remove currentQuestion++ from your submit handler.
I had the urge to restructure the questionnaire, so here is my proposal:
var questions = [];
questions.push({
question: "What does HTML stand for?",
choices: [
"Hyper Text Markup Language",
"High Text Main Language",
"Hyper Translated Modern Language"
],
answer: 0
});
questions.push({
question: "What does CSS stand for?",
choices: [
"C-Style-Source",
"Cascading Style Source",
"Cascading Style Sheets"
],
answer: 2
});
questions.push({
question: "What does JS stand for?",
choices: [
"JavaSource",
"JavaScript",
"JavaStuff"
],
answer: 1
});
// create question elements
for (var i = 0; i < questions.length; i++) {
var question = $('<div>').addClass('question');
question.append(
$('<div>').addClass('caption').text(questions[i].question)
);
var choices = $('<ul>').addClass('choices');
for (var n = 0; n < questions[i].choices.length; n++) {
var choice = $('<li>').addClass('choice');
choice.append(
$('<input>').attr('type', 'radio').attr('name', 'question' + i).val(n).attr('id', 'label_question' + i + '_' + n)
);
choice.append(
$('<label>').attr('for', 'label_question' + i + '_' + n).text(questions[i].choices[n])
);
choices.append(choice);
}
question.append(choices);
$('.questions').append(question);
}
// attach evaluation of answers
$('#submit').click(function() {
var result = $('#result');
var correctAnswers = 0;
for (var i = 0; i < questions.length; i++) {
if ( $('input[name="question' + i + '"]:checked').val() == questions[i].answer ) {
correctAnswers += 1;
}
}
result.text('You answered ' + correctAnswers + ' of ' + questions.length + ' questions correctly.').show();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="questions">
</div>
<button id="submit" type="button">
check answers
</button>
<div id="result" style="display: none;">
</div>

Matching radio button selection with nested Array content in Javascript

UPDATE 6-25-2014
Any insight would be appreciated!
UPDATE 6-21-2014
I tried to make the radio variables, global so the 'if block' in the 'answerFwd' function could be compared to the correctAnswer Array, but that didn't work!
UPDATE 6-16-2014
ADDED JS FIDDLE
I am building a quiz and creating an array of radio buttons dynamically, and would like to match the selected button with the correct answer I have established in the question array.
html
<div id="responses">
<input type="radio" name="choices" class="radioButtons" value="0" id="choice0">
<div id="c0" class="choiceText">The Observers</div>
<input type="radio" name="choices" class="radioButtons" value="1" id="choice1">
<div id="c1" class="choiceText">The Watchers </div>
<input type="radio" name="choices" class="radioButtons" value="2" id="choice2">
<div id="c2" class="choiceText">The Sentinels</div>
<input type="radio" name="choices" class="radioButtons" value="3" id="choice3">
<div id="c3" class="choiceText">The Oa</div>
</div>
questions:
var allQuestions = [{
"question": "Who was Luke's wingman in the battle at Hoth?",
"choices": ["Dak", "Biggs", "Wedge", "fx-7"],
"correctAnswer": 0 }, {
"question": "What is the name of Darth Vader's flag ship?",
"choices": ["The Avenger", "Devastator ", "Conquest", "The Executor"],
"correctAnswer": 3 },{},{} //other questions];
var item = allQuestions[0];
var currentQuestion = 0;
var playersScore = 0;
//function which creates the buttons
function createRadioButtonFromArray(array) {
var len = array.length;
var responses = document.getElementById("responses");
responses.innerHTML = '';
for (var i = 0; i < len; i++) {
radio = document.createElement("input"); //Updated 6-21-2014 removed 'var'
radio.type = "radio";
radio.name = "choices";
radio.className = "radioButtons";
radio.value = i;
radio.id = "choice" + i;
ar radioText = document.createElement("div");
radioText.id = "c" + i;
radioText.className = "choiceText";
radioText.innerHTML = array[i];
responses.appendChild(radio);
responses.appendChild(radioText);
}
}
function answerFwd() {
var answerOutput = " ";
var itemAnswers = allQuestions;
var playerTally = 0; //Updated 6-9-2014
var playerFeedback = " "; //Updated 6-9-2014
var playerMessage = document.getElementById("playerMessage"); //Updated 6-9-2014
if (currentAnswer <= itemAnswers.length) {
currentAnswer++;
}
createRadioButtonFromArray(itemAnswers[currentQuestion].choices);
* Updated 6-9-2014 I am stumped; This doesn't work but I was encouraged I got a score tally on the page! Am I comparing the elements correctly? Updated 6-21-2014 This reversed the gain, where I had the tally render on the screen*
if (itemAnswers.correctAnswer === responses.id) { //Updated 6-21-2014
playerTally += 1;
playerFeedback += "<h5>" + playerTally + "</h5> <br/>";
playerMessage.innerHTML = playerFeedback;
}
}
At first I tried to debug this but had trouble finding where the error was coming from.
One thing I noticed was currentAnswer variable was only being set once. (when it was declared)
Another thing that would make this cleaner is storing each response to each question as a property of the questions object.
For example: {"question": "What is the registry of the Starship Reliant?","choices": ["NX-01", "NCC-1864", "NCC-1701", "NCC-2000"],"correctAnswer": 1,"selectedAnswer": 0}
This is a good example of why you may want to use object oriented programming. You can keep the global namespace clean, while also having tighter control over your variables.
I put together this Quiz Code using some object oriented principles:
JavaScript
var Quiz = function(questions) {
this.questions = questions;
this.$template = {
"header": document.querySelector(".question"),
"options": document.querySelector(".question-choices")
};
this.init();
}
Quiz.prototype = {
"init": function() {
this.question = 0;
this.generateQuestion();
this.bindEvents();
},
//gets called when this.question == this.questions.length, calculates a score percentage and alerts it
"score": function() {
var correctCount = 0;
this.questions.forEach(function(question){
if ( (question.selectedAnswer || -1) === question.correctAnswer ) correctCount += 1
})
alert("Score: " + ((correctCount / this.questions.length) * 100) + "%")
},
//Gets called during initialization, and also after a nav button is pressed, loads the question and shows the choices
"generateQuestion": function() {
var question = this.questions[this.question];
this.$template.header.innerHTML = question.question;
this.$template.options.innerHTML = "";
question.choices.forEach(this.createRadio.bind(this));
},
//Binds the previous, and next event handlers, to navigate through the questions
"bindEvents": function() {
var _this = this,
$nextBtn = document.querySelector(".question-navigation--next"),
$prevBtn = document.querySelector(".question-navigation--prev");
$nextBtn.addEventListener("click", function(e) {
//Go to the next question
_this.question++;
if ( _this.question == _this.questions.length ) {
_this.score();
} else {
_this.generateQuestion();
}
});
$prevBtn.addEventListener("click", function(e) {
_this.question--;
if ( _this.question <= 0 ) _this.question = 0
_this.generateQuestion();
});
},
//Create each individual radio button, is callback in a forEach loop
"createRadio": function(choice, index) {
var question = this.questions[this.question];
var radio = document.createElement("input");
radio.type = "radio";
radio.name = "options";
radio.id = "option-"+index;
if ( question.selectedAnswer === index ) {
radio.checked = true;
}
radio.addEventListener("click", function(e) {
question.selectedAnswer = index;
})
var radioText = document.createElement("label");
radioText.setAttribute("for", "option-"+index)
radioText.innerHTML = choice;
radioText.insertBefore(radio, radioText.firstChild);
this.$template.options.appendChild(radioText);
}
}
var q = new Quiz(allQuestions)

Categories

Resources