I am a new developer and this is my first question. I am trying to make a multiple choice quiz for an assignment. I am stuck on making the NEXT button move to the next question. I think the rest of the JS file is correct...
Right now the clickNext doesn't do anything, so I need to do the following
check if the time expired (line 39)
did the user answer the question in the allotted time (line 40)
if no, try again and the clock will start over (line 60-70)
if yes, then store the answer selected - I think this part is tripping me up and I am not sure what to use here
check if the selected answer is correct (line 50-57)
if the answer is correct, move to the next question (line 52-53)
if the answer is wrong, alert "Please try again" (line 55-56)
I have tried to return the answer, the addEventListener, putting the checkAnswer function in the clickNext function
var indexQuestion = 0; // Current index of question we are on
var timer = 0; // A clock that goes up by 1 every second
var timeLastSubmit = 0; // the time we last submitted an answer
var timeExpired = false; // Did time expire for current question?
// number of seconds to wait for each question
var WAIT_TIME = 30;
// all questions to be used on the website
var QUESTIONS = [
{
"question":"Which city is the capital of Ontario?",
"choices":["New York","Toronto","Berlin","Kuala Lumpur"],
"answer":1
},
{
"question":"Which city is the capital of Canada?",
"choices":["New York","Toronto","Ottawa","Vancouver"],
"answer":2
},
{
"question":"Which continent does the south pole reside?",
"choices":["Africa","Antarctica","Asia","Australia","Europe","North America","South America"],
"answer":1
},
];
function loadApplication() {
loadQuestion(indexQuestion); // load the first question into the web page
// update the timer every second and check if question has been answered yet
setInterval(function(){
timer++;
checkExpirationTime();
},1000);
}
function clickNext() {
// make sure that the user has answered the question before the time has expired
timeLastSubmit = timer;
checkExpirationTime();
// Get the answer from drop down
var selectedIndexAnswer = getElementById('choices');
return selectedIndexAnswer;
// Get the anwer from the array
var answer = QUESTIONS[indexQuestion].choices[i];
checkAnswer();
};
function checkAnswer(){
// Compare answer. Only if correct, do you move onto next question - if(answer == QUESTIONS[indexQuestion].answer)
if(selectedIndexAnswer == answer) {
nextQuestion();
}
else {
alert('Please try again.');
}
}
function checkExpirationTime() {
// check the time, once the clock has reached 30 seconds do not move to the next quesiton
if(timer - timeLastSubmit < WAIT_TIME && !timeExpired){
document.getElementById("seconds").innerHTML = WAIT_TIME;
}
else{
timeExpired = true;
alert('Please try again.');
clearInterval(timeExpired);
}
}
function nextQuestion() {
// advance to the next question, until the there are no more questions
if(indexQuestion<QUESTIONS.length-1)
{
indexQuestion++;
loadQuestion(indexQuestion);
}
}
function loadQuestion(indexQuestion){
// grab the question
document.getElementById("question").textContent = QUESTIONS[indexQuestion].question;
// build the html string for select menu
var choices = "";
var i=0;
//loop through the choices
while(i<QUESTIONS[indexQuestion].choices.length){
// create a string of <option>answer</option><option>answer</option><option>answer</option>... and load it into the choices variable
choices += "<option>" + QUESTIONS[indexQuestion].choices[i] +"</option>";
i++;
}
document.getElementById("choices").innerHTML = choices;
}
// When the DOM is ready, run the function loadApplication();
document.addEventListener("DOMContentLoaded",loadApplication);
Right now the program does not advance to the next question, but it just stays on the first question.
To answer your first question
I am stuck on making the NEXT button move to the next question
For this you need to add click event listener to next button.
document.getElementById("btnNext").addEventListener("click",clickNext)
And the next part
I think the rest of the JS file is correct.
Almost.. You need to make a few corrections here and there.
I made some edits to the pen and is available here.
https://codepen.io/nithinthampi/pen/Yzzqqae
As, you are a learner, I would suggest not to copy it. Even the codepen I shared is not complete, but should help you to move on.
Going through your pens, here are the following issues I found with your code:
Misuse of return statements. You added a return statement in the second line of your function causing the rest of it to be completely ignored.
function clickNext() {
// make sure that the user has answered the question before the time has expired
timeLastSubmit = timer;
checkExpirationTime();
// Get the answer from drop down
var selectedIndexAnswer = getElementById('choices');
Here --> return selectedIndexAnswer;
// Get the anwer from the array
var answer = QUESTIONS[indexQuestion].choices[i];
checkAnswer();
}
onclick not added to your "Next" button, neither a addEventListener in your script was. As a result, clicking the "Next" button had no effect on your app, at all.
<button id="btnNext">Next</button>
Scoping problems. In JavaScript, when you define a variable within a scope, that variable can never be accessed from outside that very scope. Meaning defining a variable inside a function (like in your case) will not make it available in another completely separate function (unless you pass it as a parameter in some way). I'd recommend researching a bit more about JavaScript scopes to get a better of idea of how it works.
All 3 issues have been fixed in a new pen I've created for you to take a look at: https://codepen.io/MMortaga/pen/PooNNYE?editors=1010
However you might need to play a bit more with your timer, so see if you can fix it :P
Take the time to review all the changes I've mentioned and if you still face any issues just comment below, I'd be glad to help.
Related
i was wondering how to make a variable go up over time, ive tried to do this -->
var i = 1;
var c = document.getElementById("click");
function workers() {
if (click >= workers*50000)) {
click += -(workers*50000)
click += i++
c.innerHTML = click;
}
}
but it hasnt worked, how do i fix this?
you could do this
let i = 0;
// instead of 2000 insert the frequency of the wanted update (in milliseconds)
const incrementInterval = setInterval(() => i++, 2000)
// when you want it to stop it
clearInterval(incrementInterval)
anyway, i don't really understand how the code supplied with the question has anything to do with it
You have an element and a variable 'click', which tells me you're really not wanting to grow over time per se, but rather grow with every click.
Another difficulty is finding out what you're trying to do with multiplying by 50000. I am assuming you are trying to reset the count after 50000.
One big thing you're missing is the actual association of the click event to your 'click' HTML element. Below, I'm using addEventListener to do that. From there, I'm resetting the counter to '1' if 'i' goes above '5' (I use 5 just to show the reset in a reasonable number of clicks). Then I take the value of 'i' and put it into the innerHTML label of the element that triggered the event.
var i = 1;
document
.getElementById("click")
.addEventListener('click', function(e) {
if (i > 5)
i = 1;
e.target.innerHTML = `click: ${i++}`;
})
<div id='click'>click<div>
Define your question better. What is your goal? What has your code achieved? What result are you getting and how is it different than your expectations? What is 'i' meant to be used for? How does it interact with the function? Why are you multiplying it with 50000? Is workers a separate variable that's globally defined and not shown? Communication is an important skill in this field, and comments are often helpful tools to document your code for others to understand.
I think an alternative answer could be formatted in this way:
let i = 0;
function increment(){
i++;
document.querySelector('h3').textContent = i
}
document.querySelector('button').addEventListener('click',increment)
<button>Click Me</button>
<h3>0</h3>
Idea for making elements visible or invisible:
So… how the loop works right now is it for each category, it loops through each question in each category.
The idea is: Each question can be answered yes or no, and then for each question answered yes, there can be up to 5 dates added.
What I want to do:
-If yes, first date appears:
-If the first date is answered, then a second question appears, and so on.
These questions are stored in a sql server like so:
I want only the inner loop to have this ability to be visible or invisible..
My thought is to do a nested loop and check check on each element.
//Psuedo code
//For each first question which has 5 sub questions that are all set to hidden:
var questioncount = (count of the first questions)
for(int i = 0; i<questioncount; i++){
// set first variable to hold the first questions object.
var element(‘#questionElement’ + i);
// set firstElement to selected answer
var isAnsweredYes = firstElement.(‘Yes’);
for int j = 0; i<subQuestionCount; j++)
if (isAnsweredYes == True){
// jQuery selector to get an element
var query = $('#element' + j);
// check if element is Visible
var isVisible = query.is(':visible');
if (isVisible === true) {
// element is Visible
// do nothing
} else {
// element is Hidden
query.show();
}
else
{
//do nothing
}
}
}
Does my logic seem forward? or can anyone advise me in a better way?
I would use a button that says "Add another date", which is displayed under the last date field as soon as at least one is visible. That way you won't have to decide on a certain number (e.g. 5) as the maximum, plus I think it's a rather intuitive way of extending a form.
On each press of the button, create new input controls; be it in javascript or server side, it makes no real difference.
Morning all,
Definitely a novice question here, this is my first real JS project - so apologies in advance for the clunky code.
The following functions are being used to show the light sequence for a "simon" game. The code seems to work fine initially, as I've tested multiple lengths of array, however on exiting the loop I get the following error:
Uncaught TypeError: Cannot read property 'setAttribute' of null
at show (script.js:95)
at showLights (script.js:83)
at script.js:88
I've looked around a lot for fixes to this error, and the majority of feedback is that it's related to the DOM and a wrapper will fix. I've found that a wrapper doesn't resolve. Similarly, I can't see that it's an issue with the CSS or HTML as the functions work ok until exit.
The looping functions are copied below:
// iterates through simon.array then allows button press
function showLights(x) {
if (x >= simon.array.length) {
clearTimeout(timer);
show(x);
allowPress();
} else {
show(x);
var timer = setTimeout(function(){
showLights(x+1);
},500);
}
}
// adds then removes flash class to light pads.
function show(x){
var display = document.getElementById("light" + simon.array[x]);
display.setAttribute("class", "flasher");
setTimeout(function(){
display.setAttribute("class", "game-box");
},500);
}
Apologies in advance for any errors or faux pas in posting this. I strongly suspect that I'll be kicking myself when this is fixed.
Kind Regards
Andy
The issue is related to you checking the length of an array, then trying to use an element of that array that does not exist. You are possibly also trying to set an attribute to an element that does not exist.
At a guess, this is the real cause of the issue:
if (x >= simon.array.length) {
clearTimeout(timer);
show(x);
allowPress();
Simply removing show(x) should help. The reason is you are checking for the length of simon.array, then later in function show(x) you make a request for simon.array[x], but that is not going to find anything, as x is greater than the length of that array.
The other possible issue is in the following chunk, but could be solved a number of ways. One way is to check x before passing. Another is making sure the element (display) is not null before setting the attribute.
// adds then removes flash class to light pads.
function show(x){
var display = document.getElementById("light" + simon.array[x]);
display.setAttribute("class", "flasher");
setTimeout(function(){
display.setAttribute("class", "game-box");
},500);
}
My suggestion would be as follows:
// adds then removes flash class to light pads.
function show(x){
var display = document.getElementById("light" + simon.array[x]);
if (display) {
display.setAttribute("class", "flasher");
setTimeout(function(){
display.setAttribute("class", "game-box");
},500);
}
}
You may want to check out classList as well as an alternative to setAttribute.
Something else to consider instead of using setTimeout would be to use a CSS animation.
Good evening !
I am facing a strange behavior with my js/jquery, for a simple function where I am retrieving the last ID of a row, in order to check wether or not it's different from the previous one:
oldMsgId = 0;
// Ajax...
currentId = $( ".message_container tr:last" ).attr('id');
checkNewMsg(currentId);
// ... End Ajax.
function checkNewMsg(MsgId) {
if (MsgId != oldMsgId) {
var snd_msg = new Audio('sound/msg.wav');
snd_msg.volume = 0.3;
snd_msg.play();
}
oldMsgId = MsgId ;
}
The system works, however, when no new messages are retrieved, which means the latest ID is EQUAL to the old ID, it still execute the condition !
Of course, it will execute once the page is loaded because the oldMsgId is set to 0, but after that by testing with alerts, it has shown that the condition is running as it should not !
It drives me crazy, if someone has a solution I would be glad to hear it :)
EDIT : RESOLVED
Well, while using alerts inside the function this time, it appears I have made a huge mistake placing my oldMsgId var inside a loop function (which calls to ajax), so, the variable was reset to 0 everytime and thus made the difference, I'm very sorry xD!
Problem resolved, thanks everyone !
Well, while viewing with alerts inside the function this time, it appears I have made a huge mistake placing my oldMsgId var inside a loop function (which calls to ajax), I'm sorry xD!
Problem resolved, thanks everyone !
If you look here and try to click on the voting arrows, you'll see my problem. Now compare that to the homepage (click logo). Try voting there. The arrows change image based on vote. I also use a in_array() function to determine what the user has voted on and it produces the correct voting icon. This all works fine on the submission page I linked to. However, again, if you try clicking on the links, it always defaults to the else statement in this Javascript function:
I'll only show the function for liking, as I'm having the identical problem for the dislike.
function getVote(filename, num, idnum, user)
{
var like = document.getElementById('like_arrow' + num);
var dislike = document.getElementById('dislike_arrow' + num);
if (like.src.indexOf('../vote_triangle.png')!=-1 && dislike.src.indexOf('../vote_triangle_flip.png')!=-1) {
like.src = '../vote_triangle_like.png';
(AJAX to alter rating here)
} else if (like.src.indexOf('../vote_triangle.png') != -1) {
like.src = '../vote_triangle_like.png';
dislike.src = '../vote_triangle_flip.png';
(AJAX to alter rating here)
} else {
like.src = '../vote_triangle.png'; // Always defaults to this
(AJAX to alter rating here)
}
}
In case you're wondering, the num variable is what I use on the front page to differentiate between the submissions, they increment by one for each one. In this though, I just made that value blank in the function so it shouldn't affect anything. Might be my problem though, but I can't see how.
Thanks!
like.src isn't going to contain ..\. It may be as simple as removing that part.