Right now I have a few issues I need to tweak out with my Quiz Application.
When the user answers the first question, he can skip the proceeding questions.
var usersGuess = -1; //this is the starting value of the userGuess variable
This is because the userGuess variable is updated by the id of the radio button clicked when the user makes a guess, and the default starting variable is what prevents the user from skipping the first question only. I have a few ideas on how to fix it, but not sure how to implement it. One would be to detect IF none of the radio inputs are checked then don't load the next question, else load it.
When a user goes back to the question, the previous checked radio button disappears. I haven't thought of how to fix this yet. Right now I have saved the previous answers into an empty array, but I don't believe it's working properly.
Here is the code that deals with userGuess and how it interacts with the Event Listener for my next button.
nextButton.addEventListener('click', function() {
//prevent user from skipping questions
if (usersGuess === -1) {
console.log(usersGuess);
alert('You must choose an answer!');
} else {
//if users guess is the id of the correct answer, add one
if (usersGuess == questions[index].correctAnswer) {
userScore += 1;
console.log('Users Score: ' + userScore);
}
//store previous user answers into an array
usersAnswers.push(usersGuess);
if (index + 1 < questions.length) {
index++;
addQuizQuestion(questions[index].question);
addQuizAnswers(questions[index].choices);
} else {
alert('You scored a ' + getPercent() + '%!');
}
}
}, false);
Here is a link to the codepen as well for testing: http://codepen.io/laere/pen/KVwBME
Appreciate the help!
Don't complicate things too much. All you need here is the index of the current question and, say, an array of boolean (or integers, for points) for each question.
All you need to do is to check whether the current question has been answered, and if so, allow the user to move on.
Of course, since this is Javascript, all this serves for a better user experience and nothing more - if someone WANTS to move on to the next question, they WILL (unless you implement some server-side checking/question loading).
reset usersGuess to -1 before loading next question.
if (index + 1 < questions.length) {
index++;
usersGuess = -1; // reset usersGuess
addQuizQuestion(questions[index].question);
addQuizAnswers(questions[index].choices);
}
Related
In the canvas I want to be able to use the enter key to do one thing and then press it again to do another thing.
For example,
if(enterPressed) {
// do one thing
}
if (enterPressed) {
//Do some other thing
}
The problem is when I press enter once it automatically does both things at once whereas I want it to want it do each statement separately.
For more context what I want to do is similar to the style of text in pokemon games where the game will display some text then wait until you have pressed a button and then display the next set of text.
Your question is not specific to JavaScript or Canvas, but related more to general programming techniques. What you describe is different states of your program, rather than 2 actions that are done as a reaction to an event.
So think your program consist of multiple states:
Displayed first text to user -> Displayed second text to user
You will switch between these states based on certain actions user takes, in your case when they hit enter. There're many ways to hold program states, and switch between these ones, but one of the easiest ones I can give an example is, holding your text in an array and an index value that holds which one is the current index:
var currentIndex = 0;
var texts = ["This is first message", "This is second message"]
if (enterPressed) {
//you need to have boundary checks of course, skipping for simplicity
displayText(texts[currentIndex])
currentIndex++;
}
This is one way to hold the state of the program and switch between those states based on the user action.
The example code in the question has two statements in a row which I assume is how you want to handle enterPressed
To have a second (or third and more) action you will need to store the state of the enter actions. eg Is this the first press?
// this in the setup code.
var enterAction = "firstPress"
Then each time enterPressed is handled you must also check the state so that the correct action happens.
if (enterPressed && enterAction === "firstPress") {
When you handle the action you also set up the next state to be handled. Because you have two statements in a row that both check if enterPressed is true you need to also indicate that you have handled the press. This can just be setting enterPressed = false
enterAction = "secondPress";
enterPressed = false;
}
Thus you code would look like
// Init the first enter state
const FIRST = 1, SECOND = 2;
var enterAction = FIRST;
And replacing the questions code with
// Handling first press
if (enterPressed && enterAction === FIRST) {
enterAction = SECOND; // set action for next press
enterPressed = false; // clear press to indicate its been handled
// do one thing
}
// Handling second press
if (enterPressed && enterAction === SECOND) {
enterAction = FIRST; // set action for next press
enterPressed = false; // clear press to indicate its been handled
//Do some other thing
}
I have an uncertain amount of modals in my page, all determined by an specific ID. What I'm doing is checking how many times a modal gets open, and then, by using a counter, I reach a certain limit.
This limit is taken from a JSON file and then compared with the amount of times the modal has been opened.
But here's the catch. I need to save this data (the one concerning the openings) into LocalStorage, so everytime I close my browser the data remains.
As you can see, I have a "testObject" variable created in LocalStorage, this one's equal to the alertCounter. Then I compare it to my ShowingLimit variable (extracted from the JSON file) and that shows me an alert.
The question's simple. How do I keep the data from rebooting?
var alertCounter = 0;
$("#" + modalName + "").on("shown.bs.modal", function(e){
alertCounter++;
localStorage.testObject = alertCounter;
if(localStorage.testObject == showingLimit){
alert("We've reached the limit");
});
}
})
You should try something like this:
if(localStorage.testObject){ //Is there any testObject?
if(+localStorage.testObject >= showingLimit )//is equal to the limit
{
alert("We've reached the limit");//or whatever
}
else{
+localStorage.testObject++; //+ 1
}
}else{
localStorage.testObject = 1; //first time
}
Note that the + is to cast as integer, because is stored as string.
I have a simple javascript quiz set up on codepen http://codepen.io/anon/pen/dYNKJL
It displays one question per page and once you select an answer, you move onto the next question. Whatever answer is selected is given the class "active" so I can get all the selected answers at the end of the quiz.
Each answer has a data-quizIndex of either 1 or 2. When I collect all the "active" answers, I can see if they were answered data-quizIndex of 1 (first answer) or vice versa.
Anyways, up until this point, things are working great. However, I am now attempting to do something else. The user is directed to this quiz via a link, and the link will be one of the following
www.something.com/index.html?qa=0
www.something.com/index.html?qa=1
www.something.com/index.html?qa=2
The page they are coming from has a preview of question one which they can answer. Using javascript, I need to get the qa value which shouldnt be a problem. If qa is 0, the quiz starts from question 1 and nothing needs to be done. If qa is 1 or 2, the quiz should start from question two and the active class for question 1 should be set to li with data-quizIndex 1 or data-quizIndex 2 (depending on the ga value).
In other words, if they answer question one from the page that redirects them to the quiz, I need to make it so question one is answered within the main quiz application.
Would this be possible and if so, what is the best way to achieve this?
Thanks
You can define a queryString property into location, e.g:
if (typeof location.queryString === 'undefined') {
Object.defineProperty(location, 'queryString', {
get: function() {
return location.search.slice(1).split('&').map(function(i) {
var arr = i.split('=');
var a = {};
a[decodeURIComponent(arr[0])] = arr[1] ? decodeURIComponent(arr[1]) : void 0;
return a;
}).reduce(function(a, b) {
var key = Object.keys(b)[0];
a[key] = b[key];
return a;
});
}
});
}
And then, you can use it when the page is loaded, like this:
$(function() {
var qa = location.queryString['qa'];
if (qa === '1' || qa === '2') {
$('.current .quiz-answer')[qa - 1].click();
}
});
Since you want to simulate that the first question was answered, much better than repeating the code is to simulate as the user has clicked it. Take a look at your updated codepen.
Change the querystring, and loads it again, and you'll see that it's working like a charm! :)
I've been working on making a basic little image carousel in jQuery.
Currently at the moment I am stuck on the if else logic inside of my changeImage function.
When the user clicks on the "next" link then the next image in line should fade in. Luckily when I comment out the if else statement I'm able to achieve the images fading out but this is not what I am after. So we know it's a logic issue.
I'm just not sure how to implement the correct syntax with combining conditions within my if else statement and I'm sure this logic could also be much cleaner.
Please review
function changeImage (newIndex) {
var i = newIndex;
var current = i;
// `if` user clicks on next then slide image "right"
// something wrong here with my logic..
if ((newIndex === 'next') && i === (current < lengthOfImages - 1)) {
return current + 1;
}
else {
return 0;
}
// fadeout
listOfImages.fadeOut(transitionSpeed).
eq(i).fadeIn(transitionSpeed);
}
// click function on the next link
$('.next').on('click',function() {
changeImage('next');
});
Some feed back on how to fix this with a few hints towards a solution would be greatly appreciated.
JSFiddle
http://jsfiddle.net/kapena/v82pvq7x/1/
Return statement will exit the function. Anything after it will NOT run. If you want to actually return the number, you need to do it at the end.
I think you actually want to set current and not to return. Also your logic really does not make any sense. Most people would do the check like this:
current++;
if (current >= lengthOfImages) {
current = 0;
}
When 'Next' is clicked, the following is happening:
changeImage is fired, passing in 'next' as its parameter.
Within this function, a variable of i is declared and set as 'next'.
A variable of current is also being set to i, which is currently set to 'next'.
Your if statement checks to see if newIndex(the passed in parameter) is equal to 'next' as well as if i is equal to a boolean of current < lengthOfImages - 1. This is evaluating to a boolean, and i is not a boolean. This is why your function is not firing appropriately.
Your return statements in your conditionals are causing your function to complete, making it so your fadeOut and fadeIn transitions never get a chance to execute.
This part
if ((newIndex === 'next') && i === (current < lengthOfImages - 1))
is always false:
i = 'next'
current = 'next'
(current < lengthOfImages - 1) is a boolean
therefore the === is always false, and flow goes to the return clause.
I actually just spent a really long time figuring out answers to this question by piecing it together from the spotty documentation and a lot of web console inspection. Since by far the most useful information came from Stack Overflow, I wanted to put this question, and its answer, here for the future benefit of anyone else searching.
The question is, how can you add javascript to a question that will immediately save that question's answer into an embedded data field? Immediately, as in, not waiting until the next Qualtrics.SurveyEngine.AddOnLoad(). This involves the sub-question of how can you add javascript to a survey question and have it run when the Next button is clicked? And the sub-question of, how can you save embedded data fields that are dynamically named based on the question ID?
Caveat Emptor: all this javascript hacking is not explicitly supported by Qualtrics, so the code here may stop working eventually.
Here is how to get the response value of a slider and save it in an embedded data field with a name that is numbered based on the question ID. This way only works if the text input box for the slider is visible. There's probably a way to do it without that, too, maybe someone else can add that to the answers.
Qualtrics.SurveyEngine.addOnload(function()
{
// everything here runs when the page is loaded. So, we can get the Question ID here,
// but we can't get the response value until later.
var currentQuestionID = this.getQuestionInfo().QuestionID
//var resultEmbeddedName = currentQuestionID + "_result" //e.g. QID6_result
var resultEmbeddedName = "result_" + currentQuestionID.substring(3) //e.g. result_6
$('NextButton').onclick = function (event) {
// everything in here will run when you click the next button
// note that it has access to javascript variables from the enclosing function
// however, if you declare something in here with "var" then it will be a LOCAL variable
// the following alert will appear when you click the next button. For me, it appears twice;
// I'm not sure why.
// Save the current question's response value
var responseTextField = document.getElementById(currentQuestionID + '~1~result')
var currentResponse = responseTextField.value
alert("Result: " + currentResponse + "\nwill be available to future questions as: \n$" + "{e://Field/" + resultEmbeddedName + "}")
Qualtrics.SurveyEngine.setEmbeddedData(resultEmbeddedName, currentResponse)
// and now run the event that the normal next button is supposed to do
Qualtrics.SurveyEngine.navClick(event, 'NextButton')
}
});
For multiple choice items, it's a bit more complicated. Here's the code that works, with lots of comments and demos. Note that the variable "currentResponse" ends up holding the NUMBER of the chosen choice, while "currentChoiceText" ends up holding the text label for that choice (e.g. Yes or No.) So you can save whichever one you prefer.
Qualtrics.SurveyEngine.addOnload(function()
{
// everything here runs when the page is loaded. So, we can get the Question ID here,
// but we can't get the response value until later.
var currentQuestionID = this.getQuestionInfo().QuestionID
console.log("Current Question ID is: " + currentQuestionID)
//var resultEmbeddedName = currentQuestionID + "_result" //e.g. QID6_result
var resultEmbeddedName = "result_" + currentQuestionID.substring(3) //e.g. result_6
$('NextButton').onclick = function (event) {
// everything in here will run when you click the next button
// note that it has access to javascript variables from the enclosing function
// however, if you declare something in here with "var" then it will be a LOCAL variable
// the following alerts will appear when you click the next button. For me, it appears twice;
// I'm not sure why.
// Save the current question's response value
var questionObject = Qualtrics.SurveyEngine.getInstance(currentQuestionID)
var currentResponse = questionObject.getSelectedChoices()[0] //in case more than one is selected, it will only work here to take one!
var theQuestionInfo=questionObject.getQuestionInfo()
var choicesObject=theQuestionInfo.Choices
var thisChoiceObject=choicesObject[currentResponse]
var currentChoiceText=thisChoiceObject.Text
console.log("Number of the current choice is " + currentResponse)
console.log("Text of the current choice is " + currentChoiceText)
alert("Result: " + currentChoiceText + "\nwill be available to future questions as: \n$" + "{e://Field/" + resultEmbeddedName + "}")
Qualtrics.SurveyEngine.setEmbeddedData(resultEmbeddedName, currentChoiceText)
// and now run the event that the normal next button is supposed to do
Qualtrics.SurveyEngine.navClick(event, 'NextButton')
}
});
Both of these refer to the question ID dynamically, so they will work individually if you copy the question to a new one. Without needing to change any of the javascript code.
To test these, make a slider question or a multiple choice question and add the respective javascript. Then, make another slide after a page break (the page break is necessary to cause the appearance of the Next button). In that slide, put a piped text field like ${e://Field/result_1} or whatever the alert dialog tells you the saved value will be. When you preview the survey, you should see the value that was entered on the first question, in the piped text field of the second question.
As far as this demo goes, you could certainly achieve the same effect with just piped text. But if you have some reason that you want a question to actually immediately save its response into embedded data, this will do that for you.
Also, if you need to know how to run code when the Next button is clicked, this can be adapted for any general need for that.
I was having problems that calling the below code in the $('NextButton').onclick method was forcing $('NextButton').onclick method to be called twice. Removing it worked for me so the onclick method gets called only once but still moves the survey forward.
// and now run the event that the normal next button is supposed to do
Qualtrics.SurveyEngine.navClick(event, 'NextButton')
This works each time you press the "Next" button. Hope that helps!
Qualtrics.SurveyEngine.addOnload(function(){
var nextButton =document.getElementById("NextButton");
if (nextButton!=null){
$("NextButton").on("click", function(event) {
alert("Hello World!");
});
}
});