Using jQuery to Create True and False Questionnaire [closed] - javascript

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I'm trying to figure out the best way to build a questionnaire. See below.
http://cl.ly/image/1W2M3J2z2q2E
http://cl.ly/image/2m461g200b0X
This is what I've got in my code, and it works just fine but as you can see, it gets incredibly long after just two questions. What is the best way to condense this code, so that I do not repeat myself so many times.
// find all anchor tag and prevent default behavior
$('.questions').find('a').on('click', function(e){
e.preventDefault();
});
var ques1 = $('#question1'),
q1 = $('.question1'),
q1True = $('.question1-true').hide(),
q1False = $('.question1-false').hide();
var ques2 = $('#question2'),
q2 = $('.question2').hide(),
q2True = $('.question2-true').hide(),
q2False = $('.question2-false').hide();
(function () {
// click button false
$('#question1 .btn-false').on('click', function(){
q1.hide();
q1True.fadeIn();
});
// click button true
$('#question1 .btn-true').on('click', function(){
q1.hide();
q1False.fadeIn();
});
// click previous button
$('#question1 .prev').on('click', function(){
q1True.hide();
q1False.hide();
q1.show();
});
// click next button
$('#question1 .next').on('click', function(){
ques1.hide();
q2.show();
}); //end question1
// begin question 2
$('#question2 .btn-false').on('click', function(){
ques2.show();
q2.hide();
q2True.show();
});
$('#question2 .btn-true').on('click', function(){
ques2.show();
q2.hide();
q2False.show();
});
})();

Just to give you an idea:
LIVE DEMO
HTML:
<div id="QA">
<div id="qDIV">
<h2></h2>
<button>False</button>
<button>True</button>
</div>
<div id="response">
<p></p>
<button id="prev">Back</button>
<button id="next">Next</button>
<button id="score">Score</button>
</div>
</div>
<pre></pre>
Let's now create an Array of object literals to store data:
var questionnaire = [
{
"question" : "The Earth is round.",
"response" : "The Earth is round!",
"correct" : 1 // 0=False, 1=True
},
{
"question" : "The 'cravat' is originally from France.",
"response" : "The 'cravat' is from Croatia!",
"correct" : 0
},
{
"question" : "Is Java == JavaScript?",
"response" : "It's a different language.",
"correct" : 0
} // Add comma and more objects.
];
This way we can always keep track of the values and inject at every stage an user answer into our current question object.
var $qDIV = $('#qDIV'),
$rDIV = $('#response'),
$qH2 = $("h2", $qDIV),
$answer = $("button", $qDIV),
$response = $("p", $rDIV),
tot = questionnaire.length,
c = 0; // Current Q array counter
function QandA( idx ){
$qDIV.fadeTo(600,1);
$rDIV.hide();
var currQ = questionnaire[c]; // The Object literal from Array
var isCorrect = currQ.correct; // 0 or 1?
var answerIsCorrect = idx==isCorrect; // (compare values) Returns boolean
var resp = answerIsCorrect ? "Great!" : "Wrong!";
currQ.answer = idx; // Put user answer into object (0 or 1)
$qH2.text( (c+1) +'. '+ currQ.question );
$response.text( resp +' '+ currQ.response );
}
QandA();
$answer.click(function(){
var idx = $answer.index(this); // 0 or 1 (get button index)
QandA( idx );
$rDIV.fadeTo(600,1);
$qDIV.hide();
console.log( JSON.stringify(questionnaire, null, 2) ); // TEST ONLY
});
$('#prev, #next').click(function(){
c = this.id=='next' ? ++c : c ; // advance or repeat Question
QandA();
$('#next').toggle(c<tot-1);
$('#score').toggle(c>=tot-1);
});
$('#score').click(function(){
$('pre').text( JSON.stringify(questionnaire, null, 2) ); // TEST
c = 0; // reset questionnary to first question
QandA(); // Restart
});
Previous answer:
LIVE DEMO
having this trivial HTML:
<div id="QA">
<h2></h2>
<span id="buttons"></span>
<p>Points : <span>0</span></p>
</div>
Let's create an array of object literals like:
var questionnaire = [
{
"question" : "The earth is...",
"valid" : 1, // indicates the correct array number, use 0, 1...
"buttons" : ["A cube", "Round"],
"answers" : [ "Ohh, c'mon...", "You got it! It's round!"]
},
{
"question" : "The Cravat is originally from:",
"valid" : 0,
"buttons" : ["Croatia", "France", "Germany"],
"answers" : [ "Great", "Wrong, it's from Croatia!", "Wrong... Sorry"]
},
{
"question" : "Is Java == JavaScript?",
"valid" : 0,
"buttons" : ["False", "True"],
"answers" : ["Exatcly!", "Ohh, c'mon..."]
} // add comma and more Object literals...
];
In the above you can create as many possible buttons and answers you want. jQuery will create the buttons out of the needed object Array. Than you set a valid pointer to tell the questionnaire logic which of the answers index is the correct one using 0, 1, 2....
After jQ creates our buttons, on a button click you can retrieve it's index and target the needed answer out of your object literal, and to determine the points see if the clicked button index matches your valid value.
As you can see you can advance your questions by incrementing a counter variable after every button click (we'll call qc):
var $qa = $('#QA'),
$question = $("h2", $qa),
$buttons = $("#buttons", $qa),
$points = $("p>span",$qa),
questionnaireLength = questionnaire.length, // How many Q?
qc = 0, // Current Question counter
points = 0; // Current points
function QandA(){
var quest = questionnaire[qc],
question = quest.question,
validIdx = quest.valid,
btns = quest.buttons,
answer = quest.answers;
$question.text( question );
if(qc >= questionnaireLength){
return alert("game over");
}
// generate buttons with text:
$buttons.empty();
for(var i=0; i<btns.length; i++){
$buttons.append("<button>"+ btns[i] +"</button>");
}
// Retrieve generated buttons
var $btn = $("button", $buttons);
// Assign click
$btn.one('click', function(){
var idx = $btn.index(this); // get button index
alert("(valid idx is: "+ validIdx +" Clicked button idx: "+ idx +")");
alert("Game says: "+ answer[idx] );
points += (idx === parseInt(validIdx, 10) ? 5 : -5);
$points.text( points );
// Next question
qc++; QandA(); // increment question counter and set new game
});
}
QandA(); // Start game

Related

How to iterate over unique id names without hardcoding?

I am making a quiz. I would like to iterate over the different buttons to bring up different questions once I press the buttons. However, since each button has a different id, I am finding it difficult to find a way of changing the id names in the loop. See below for code:
let mybtn1 = document.getElementById("myBtn1")
let questions = [
{
question : "What is an Epidemics?",
choiceA : "CorrectA",
choiceB : "WrongB",
choiceC : "WrongC",
choiceD: "Hello",
correct : "Hello"
},{
question : "What does CSS stand for?",
choiceA : "Wrong",
choiceB : "Correct",
choiceC : "Wrong",
correct : "B"
},{
question : "What does JS stand for?",
choiceA : "Wrong",
choiceB : "Wrong",
choiceC : "Correct",
correct : "C"
}
];
mybtn1.addEventListener("click", pressbtn);
function pressbtn(){
modal.style.display = "block";
questionText.innerHTML = questions[0].question;
answerA.innerHTML = questions[0].choiceA;
answerB.innerHTML = questions[0].choiceB;
answerC.innerHTML = questions[0].choiceC;
answerD.innerHTML = questions[0].choiceD;
}
<ul class="path-one-row">
<li class="grid blue" id="myBtn1"></li>
<li class="grid blue" id="myBtn2"></li>
<li class="grid blue" id="myBtn3"></li>
<li class="grid blue" id="myBtn4"></li>
</ul>
For example, when I click the button with id='mybtn1', it should iterate to give me access to questions[0] and so then I can manipulate the innerHTML. For id='mybtn2', questions[1] and so on. How could I write a loop to help me iterate this?
You can just give the buttons the same class or data-attribute, and you can select them with querySelectorsAll and loop through, and with its index, you can iterate through.
For example all button has the data-question attribute.
Get them like
const questions = document.querySelectorsAll('[data-question]')
And loop through
questions.forEach((index) => {
question.addEventListener("click", () => pressbtn(index));
function pressbtn(index){
modal.style.display = "block";
questionText.innerHTML = questions[index].question;
answerA.innerHTML = questions[index].choiceA;
answerB.innerHTML = questions[index].choiceB;
answerC.innerHTML = questions[index].choiceC;
answerD.innerHTML = questions[index].choiceD;
}
})
Well, there are several ways to make that. Using vanilla javascript you can call a function when clicking a button, pass the id to the function and create the li with that data
<button id="0" click = changeButtons(id)>
<ul id="buttonList>
</ul>
//change buttons
changeButtons (id){
let list =document.getElementbyId(buttonList)
let questions = []
questions[id].forEach(question => {
list.innerHtml += <li><button> question</button> </li>
})
}
note that you have to alter your json to make an array with the questions, you also can use keys to make an array with your questions keys and access to that

WP Media Library - Select function not updating row index for ID update

I am working on a wordpress blog with a custom metabox on the edit page of each post.
This metabox consists of table with each row containing image src selected from media library.
Now every new row added has an id :
row 1 : img_metabox_src_0
row 2 : img_metabox_src_1
row 3 : img_metabox_src_2
Table headers goes like :
----Image < img >------ |------- URL (Input textbox)------ | -------- Select Image (Input submit)------ | -----Delete Image (Input submit)--------
Now,
On click on "Select Image" on any row, I retrieve the row index from jquery, and then send : "img_metabox_src_"+index to file_frame.on( 'select', function() for url update.
i.e.
jQuery('tr #select_image').off().on('click', function( event ){
event.preventDefault();
var row_index = jQuery(this).closest('tr').index();
var id = "img_metabox_src_" + row_index;
//******** 1 ***********
console.log('row_index');
console.log(row_index);
console.log(id);
console.log(jQuery('#' + id));
if ( file_frame ) {
file_frame.open();
return;
}
file_frame = wp.media.frames.file_frame = wp.media({
title: "Select/Upload Image",
button: {
text: "Select",
},
library : { type : 'image'},
multiple: false
});
file_frame.on( 'select', function() {
attachment = file_frame.state().get('selection').first().toJSON();
// "mca_features_tray" is the ID of my text field that will receive the image
// I'm getting the ID rather than the URL:
// but you could get the URL instead by doing something like this:
//******** 2 ***********
console.log(id);
console.log(jQuery('#' + id));
jQuery('#' + id).attr('value',attachment.url);
id = null;
});
Now,
Case 1 : When I FIRST click with row index3, the URL updates on img_metabox_src_3.
Case 2 : But after that whichever row i click, the url updates on img_metabox_src_3.
Also on adding logs, I get
(for Case 2, say I clicked row index 1) :
//******** 1 ***********
row index : 1
id : img_metabox_src_1
//******** 2 ***********
id : img_metabox_src_3
i.e. inside file_frame.on( 'select', function() {,
the ID value changes to first clicked value.
Please help on how to pass updated row index/id to the select function
Thanks, I used global concept :
function set_row_index (ind){
row_index = ind;
}
function get_row_index(){
return row_index;
}
jQuery(document).ready(function(){
jQuery('tr input.select_media_library').off().on('click', function( event ){
event.preventDefault();
var index = jQuery(this).closest('tr').index();
**set_row_index(index);**
.
.
.
file_frame.on( 'select', function() {
attachment = file_frame.state().get('selection').first().toJSON();
**index = get_row_index();**
var id = "img_src_" + index;
jQuery('#' + id).attr('value',attachment.url);
});
file_frame.open();
});

I want to compare that old and new value are same or not for input textbox in angularjs?

I have two input box in angularjs html structure.
When I click on my button or a tag I want my textbox old and new value in angularjs or I want to compare that old and new value are same or not.
I'm using angular 1.4.7.
<input phone-input ng-show="mode == 'edit'" ng-model="leader.work"/>
<input phone-input ng-show="mode == 'edit'" ng-model="leader.mobile"/>
<a ng-show="mode == 'edit'" ng-click="mode = null;save_profile(leader)" style="cursor: pointer" title="Save">Save</a>
$scope.save_profile = function (leader) {
/* How to get/compare both text box old and new value are same or not*/
};
try this
function TodoCrtl($scope) {
$scope.newValue = 'Initial Text';
$scope.save_profile = function(newvalue, oldvalue) {
//Here you can access old value and new value from scope.
$scope.new = 'New Value :' + $scope.newValue;
$scope.old = 'Old Value :' + $scope.oldValue;
//After accessing update the scope old value to new value with function parameters
$scope.newValue = newvalue;
$scope.oldValue = newvalue;
};
$scope.changeValue = function() {
$scope.newValue = 'Dynamic Change';
};
}
<!DOCTYPE html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
<meta charset=utf-8 />
<title>ng-click</title>
</head>
<body>
<div ng-controller="TodoCrtl">
<input type=text ng-model="newValue" ng-init="oldValue=newValue">
<button ng-click="save_profile(newValue,oldValue)">Save</button>
<div>{{new}}</div>
<div>{{old}}</div>
<br>
<button ng-click="changeValue()">Change Dynamic</button>
</div>
</body>
</html>
The simplest possible approach which will work in all occasions is to make a copy of the leader when you load it and compare current leader with the copy you made when you press the button.
function TodoCtrl($scope) {
// initialization
var originalLeader = null;
$scope.leader = null;
$scope.mode = 'edit';
// this is where you get your leader data, in my example
// I simply set it to demo data but you can load the
// data using AJAX for example
var loadLeader = function() {
var leaderData = {
mobile: '000',
work: '111'
};
originalLeader = angular.copy(leaderData);
$scope.leader = leaderData;
}
// loadLeader will be invoked on page load
loadLeader();
$scope.save_profile = function (leader) {
// you have access to your original data and current data,
// you can compare them and do whatever you want with them
console.log('originalLeader ', originalLeader);
console.log('leader ', leader);
// for example
if ( leader.mobile != originalLeader.mobile ) {
alert('Mobile has changed from ' + originalLeader.mobile + ' to ' + leader.mobile);
}
};
}
Some answers suggested to use $scope.$watch, you can implement your solution using that but you need to be careful as the $scope.$watch callback will be invoked on each change. To illustrate what I mean let's add something like this to your code:
$scope.$watch('leader.mobile', function(newVal,oldVal) {
console.log('newVal ', newVal);
console.log('oldVal ', oldVal);
});
Let the leader.mobile be 000 at the init time.
You type 1 to the text box, now leader.mobile is 0001, the callback function will be invoked and the log will be:
newVal 0001
oldVal 000
Now you press backspace and delete 1 you previously typed, the leader.mobile variable is now 000 and the log is:
newVal 000
oldVal 0001
Your current data is same as starting data but the $scope.$watch was invoked twice and is difficult to determine if data has really changed or not. You would need to implement some additional code for that, something like this:
// be careful about this, you need to set to null if you reload the data
var originalMobile = null;
$scope.$watch('leader.mobile', function(newVal,oldVal) {
// set originalMobile to value only if this is first
// invocation of the watch callback, ie. if originalMobile
// was not set yet
if ( originalMobile == null ) {
originalMobile = oldVal;
}
});
$scope.save_profile = function(leader) {
if ( leader.mobile != originalMobile ) {
// ...
}
}
You can use the $watch function. The link below will show you how to implement it. You can get an old and new value with it.
How do I use $scope.$watch and $scope.$apply in AngularJS?

Making a quiz with Javascript. Getting array values from and object.

Im trying to create a simple quiz with Javascript. I am struggling to grasp the concept of how to iterate over the values of an array from an object. I eventually want to display a radio button with its value as the choice of answers. If someone could point me in the right direction i would really appreciate it.
Fiddle: http://jsfiddle.net/Renay/eprxgxhu/
Here is my code:
HTML
<h1> General Knowledge Quiz </h1>
<h2 id='questionTitle'> </h2>
<ul id ='selectionList'> </ul>
<p> Click the next button to go to the next question! </p>
<button type="button" id = nextButton> Next </button>
</div>
Javascript
var allQuestions = [{
question: 'What is the capital city of Australia?',
choices: ['Sydney', 'Melbourne', 'Canberra', 'London'],
correctAnswer: 2
},
{
question: 'Who won the 2014 FIFA World Cup?',
choices: ['Brazil', 'England', 'Germany', 'Spain'],
correctAnswer: 2
},
{
question: 'What book series is authored by J.K Rowling?',
choices: ['Game of Thrones', 'Hunger Games', 'Twilight', 'Harry Potter'],
correctAnswer: 3
},
{
question: 'The Eiffel Tower is located in which following country?',
choices: ['Italy', 'France', 'Iceland', 'Mexico'],
correctAnswer: 1
}];
//Reference to tags
var questionTitle = document.getElementById('questionTitle');
var selectionList = document.getElementById('selectionList');
var nextButton = document.getElementById('nextButton');
//Initiating some variables
var i = 0;
var length1 = allQuestions.length;
var correctAnswer = 0;
function populateQuestion() {}
Firstly attach click event to next button and give call to populateQuestion() using counter to iterate through allQuestions array and use i as counter variable.
nextButton.onclick = function() {
/*itterate through questions*/
if(i>allQuestions.length -1){/*go to first when reached last*/
i=0;
}
populateQuestion(i);
i++;
};
Iterate through allQuestions array for question title and choices as:
function populateQuestion(qNum) {
var individualQuestion = allQuestions[i];
questionTitle.innerText = individualQuestion.question;
selectionList.innerHTML = ""; //reset choices list
for(key in individualQuestion.choices){
var radioBtnName = "question"+i+"_choice";
var choiceText = individualQuestion.choices[key];
selectionList.appendChild(createLi(radioBtnName,choiceText));
}
}
Write dynamic li and radio button creation function as:
function createLi(name, choiceText) {
var e = document.createElement('li');
var radioHtml = '<input type="radio" name="' + name + '"';
radioHtml += '/>';
radioHtml += choiceText;
e.innerHTML = radioHtml;
return e;
}
Please refer to this fiddle for same.
You need to associate an onClick event with your button to call the relevant part of the JavaScript. Go through the example here
On another note, using JavaScript for a quiz might not be a good idea as one can see the answers using view-source. I would suggest using PHP to fetch results from a database.

populating select dropdowns dependent on change event

Hi I'm nearly finished with my small task of populating select dropdowns then outputting a relevant number. The select a company etc works.
Here's my JSFiddle: http://jsfiddle.net/3MK3D/1/
I need to now generate the appropriate companies in the select dropdown dependent on which sector is selected. I've created a new javascript array for personal companies.
I've thought of maybe doing something like this and passing the correct variable to the appropriate function but not really sure how to implement it:
var companiesArray;
$('#sector').on('change', function(e){
var optionSelected = $("option:selected", this);
var sectorSelected = this.value;
if( sectorSelected == 'business' ) {
companiesArray = 'insurancecompanies';
} else if( sectorSelected == 'personal' ) {
companiesArray = 'personalcompanies';
} else {
}
});
There is probably a better way?
Use a companies object that has your sector select values as keys to the relevant arrays:
var companies = {
business : [
{
name : 'Advent',
property : '01242 674 674',
fleet : '',
motortrade : ''
},
{
name : 'Allianz',
property : '0844 412 9988',
fleet : '0800 587 5858',
motortrade : ''
},
// other insurance companies
],
personal : [
// personal companies
]
}
Then:
$('#sector').on('change', function(e){
var optionSelected = $("option:selected", this);
var sectorSelected = this.value;
var companyArray = companies[sectorSelected];
// iterate over companyArray and create the relevant option objects for #company
});

Categories