This is a weird one to me. I'm currently creating a multiple choice quiz using js/jquery, and I've found that if I enter a question that is greater than 105 characters in length, the script just doesn't run & no buttons can be clicked.
For example, using the code I've provided this will run absolutely fine and I can have a multiple choice quiz working fine. However, changing the question to a different that is over 105 characters breaks it.
For example, if I changed
"Multiple choice q1"
to
"The process ‘PopularScreenSavers.exe’ is running in the background of a user's laptop. What could this be an example of? " (a question I want to include)
essentially stops my script from running at all.
Included below is the current js as well as a snippet of the relevant html body. It all works perfectly fine... except when I want a longer question.
Any help would be appreciated.
CODE
(function() {
const myQuestions = [
{
question: "The process ‘PopularScreenSavers.exe’ is running in the background of a user's laptop. What could this be an example of? ",
answers:
{
a: "a",
b: "b",
c: "c",
d: "d"
},
correctAnswer: "a"
},
{
question: "Multiple choice q1",
answers:
{
a: "",
b: "",
c: "",
d: ""
}
}];
function buildQuiz()
{
const output = [];
myQuestions.forEach((currentQuestion, questionNumber) =>
{
const answers = [];
for (letter in currentQuestion.answers)
{
answers.push(`<label>
<input type="radio" name="question${questionNumber}" value="${letter}">
${letter} :
${currentQuestion.answers[letter]}
</label>`);
}
output.push(`<div class="slide">
<div class="question"> ${currentQuestion.question} </div>
<div class="answers"> ${answers.join("")} </div>
</div>`);
});
quizContainer.innerHTML = output.join("");
}
function showResults()
{
const answerContainers = quizContainer.querySelectorAll(".answers");
let numCorrect = 0;
myQuestions.forEach((currentQuestion, questionNumber) =>
{
const answerContainer = answerContainers[questionNumber];
const selector = `input[name=question${questionNumber}]:checked`;
const userAnswer = (answerContainer.querySelector(selector) ||
{}).value;
if (userAnswer === currentQuestion.correctAnswer)
{
numCorrect++;
answerContainers[questionNumber].style.color = "#009A44";
answerContainers[questionNumber].style.fontWeight = "900";
}
else
{
answerContainers[questionNumber].style.color = "#DA291C";
answerContainers[questionNumber].style.fontWeight = "900";
}
});
resultsContainer.innerHTML = `${numCorrect} out of ${myQuestions.length}`;
}
function showSlide(n)
{
slides[currentSlide].classList.remove("active-slide");
slides[n].classList.add("active-slide");
currentSlide = n;
if (currentSlide === 0)
{
previousButton.style.display = "none";
}
else
{
previousButton.style.display = "inline-block";
}
if (currentSlide === slides.length - 1)
{
nextButton.style.display = "none";
submitButton.style.display = "inline-block";
}
else
{
nextButton.style.display = "inline-block";
submitButton.style.display = "none";
}
}
function showNextSlide()
{
showSlide(currentSlide + 1);
}
function showPreviousSlide()
{
showSlide(currentSlide - 1);
}
const quizContainer = document.getElementById("quiz");
const resultsContainer = document.getElementById("results");
const submitButton = document.getElementById("submit");
buildQuiz();
const previousButton = document.getElementById("previous");
const nextButton = document.getElementById("next");
const slides = document.querySelectorAll(".slide");
let currentSlide = 0;
showSlide(0);
submitButton.addEventListener("click", showResults);
previousButton.addEventListener("click", showPreviousSlide);
nextButton.addEventListener("click", showNextSlide);
})();
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<div class="quiz-container">
<div id="quiz"></div>
</div>
<button id="previous">Previous Question</button>
<button id="next">Next Question</button>
<button id="submit">Submit Quiz</button>
<div id="results"></div>
Edit: adding that this runs as valid js, but it doesn't run in Chrome - should have specified, apologies.
jsfiddle
These fiddles should show the issues I'm having:
Working - https://jsfiddle.net/3m5afcuo/
Not working (only change made was to the string) - https://jsfiddle.net/su3hptdq/
Related
I'm building a small quiz app, and want to display the user score on a different html page immediately the user finished answering the questions. what am getting right now the user finish answering the questions the in which the score is suppose to display loads and open without the score displayed.
`
<body>
<div class="quiz-title">
<h1>JS Quiz</h1>
</div>
<div class="container">
<h2 id="score-board">00</h2>
<div id="questions"></div>
<div id="answers">
</div>
<button type="submit"class="nbtn">Play</button>
</div>
<script src="quiz.js"></script>
<!-- <script type="text/javascript" src="quiz1.js"></script> -->
</body>
the page to display the score
<body>
<h2 id="score-board">00</h2>
<div>
<button id="play-btn">play</button>
</div>
<script src="quiz.js"></script>
<!-- <script type="text/javascript" src="quiz1.js"></script> -->
</body>
var questionElement = document.getElementById('questions');
var answerElement = document.getElementById('answers');
var scoreBoard = document.querySelector('#score-board');
const state = {
currentQuestionIndex: 0,
score: 0
};
var questions = [
{ question: " 1. javaScript is an....... language?",
answers: [ "object-oriented", "object-based", "procedural", "none of the above"],
correct: 1
},
{ question: " 2.which of the following keywords is used a define variable in javaScript",
answers: [ "var", "let", "both A and B", "none of the above"],
correct: 2
},
{
question: "3. which of the following methods is used to HTML elements using javaScript",
answers: ["getElementsById", "getElementByClassName", "both A and B", "none of the above"] ,
correct: 2
}
];
function showQuestion(questionIndex){
const question = questions[questionIndex];
let qDiv = document.createElement('div');
let p = document.createElement('p');
questionElement.innerHTML = "";
answerElement.innerHTML = "";
p.textContent = question.question;
qDiv.appendChild(p);
questionElement.appendChild(qDiv);
question.answers.forEach((answers, answerIndex) =>{
const $input = document.createElement('input');
const $label = document.createElement('label');
$label.appendChild($input);
$label.appendChild(document.createTextNode(answers));
$input.name = `question${questionIndex}`;
$input.type = 'radio';
$input.value = answerIndex;
answerElement.append($label);
// if ($input.checked === false) {
// console.log('select answer');
// } else{
// showQuestion(state.currentQuestionIndex);
// }
});
};
showQuestion(0);
var nBtn = document.querySelector('.nbtn');
nBtn.addEventListener('click', function(){
state.currentQuestionIndex += 1;
if (state.currentQuestionIndex === questions.length) {
removeLastQuestion();
scorePage();
showScores();
} else{
showQuestion(state.currentQuestionIndex)
}
});
const $answers = document.getElementById("answers");
$answers.addEventListener("change", (event) => {
const currentQuestion = questions[state.currentQuestionIndex];
const selectedAnswerIndex = Number(event.target.value);
const correctAnswerIndex = currentQuestion.correct;
const isCorrect = selectedAnswerIndex === correctAnswerIndex;
state.score += isCorrect ? 1 : 0;
// if (isCorrect) {
// var scoreBoard = document2.querySelector('.score-board');
// // scoreBoard.textContent = state.score;
// // console.log("correct answer");
// } else {
// var scoreBoard = document.querySelector('.score-board');
// // scoreBoard.textContent = state.score += 0;
// // console.log("wrong answer");
// }
});
function showScores() {
if (state.currentQuestionIndex === questions.length) {
scoreBoard.innerHTML = `${state.score}/${questions.length}`
}
}
function removeLastQuestion(){
if (state.currentQuestionIndex > questions.length - 1) {
questionElement.innerHTML = "";
answerElement.innerHTML = "";
}
}
function scorePage() {
if (state.currentQuestionIndex > questions.length -1) {
window.location.href = 'index23.html';
// scoreBoard = document.querySelector('#score-board');
// scoreBoard.innerText = `${state.score}/${questions.length}`;
}
}
// const playBtn = document.querySelector('#play-btn');
// playBtn.addEventListener('click', showQuestion);
`
im currently trying to create a picture quiz that utlises this tutorial https://www.sitepoint.com/simple-javascript-quiz/
the issue I am having is changing this quiz from a solely text based affair into a picture quiz. for example the quiz will ask a question such as "which of these pictures is a giraffe?", the user then will have to select an answer that has a giraffe picture.
Below is the current version of the js script i have (admittedly, not much has changed, due to not being able to figure images out)
(function(){
// Functions
function buildQuiz(){
// variable to store the HTML output
const output = [];
// for each question...
myQuestions.forEach(
(currentQuestion, questionNumber) => {
// variable to store the list of possible answers
const answers = [];
// and for each available answer...
for(letter in currentQuestion.answers){
// ...add an HTML radio button
answers.push(
`<label>
<input type="radio" name="question${questionNumber}" value="${letter}">
${letter} :
${currentQuestion.answers[letter]}
</label>`
);
}
// add this question and its answers to the output
output.push(
`<div class="slide">
<div class="question"> ${currentQuestion.question} </div>
<div class="answers"> ${answers.join("")} </div>
</div>`
);
}
);
// finally combine our output list into one string of HTML and put it on the page
quizContainer.innerHTML = output.join('');
}
function showResults(){
// gather answer containers from our quiz
const answerContainers = quizContainer.querySelectorAll('.answers');
// keep track of user's answers
let numCorrect = 0;
// for each question...
myQuestions.forEach( (currentQuestion, questionNumber) => {
// find selected answer
const answerContainer = answerContainers[questionNumber];
const selector = `input[name=question${questionNumber}]:checked`;
const userAnswer = (answerContainer.querySelector(selector) || {}).value;
// if answer is correct
if(userAnswer === currentQuestion.correctAnswer){
// add to the number of correct answers
numCorrect++;
// color the answers green
answerContainers[questionNumber].style.color = 'lightgreen';
}
// if answer is wrong or blank
else{
// color the answers red
answerContainers[questionNumber].style.color = 'red';
}
});
// show number of correct answers out of total
resultsContainer.innerHTML = `${numCorrect} out of ${myQuestions.length}`;
}
function showSlide(n) {
slides[currentSlide].classList.remove('active-slide');
slides[n].classList.add('active-slide');
currentSlide = n;
if(currentSlide === 0){
previousButton.style.display = 'none';
}
else{
previousButton.style.display = 'inline-block';
}
if(currentSlide === slides.length-1){
nextButton.style.display = 'none';
submitButton.style.display = 'inline-block';
}
else{
nextButton.style.display = 'inline-block';
submitButton.style.display = 'none';
}
}
function showNextSlide() {
showSlide(currentSlide + 1);
}
function showPreviousSlide() {
showSlide(currentSlide - 1);
}
// Variables
const quizContainer = document.getElementById('quiz');
const resultsContainer = document.getElementById('results');
const submitButton = document.getElementById('submit');
const myQuestions = [
{
question: "Who invented JavaScript?",
answers: {
a: "Douglas Crockford",
b: "Sheryl Sandberg",
c: "Brendan Eich"
},
correctAnswer: "a"
},
{
question: "is my name davet?",
answers: {
a: "Douglas Crockford",
b: "Sheryl Sandberg",
c: "yes"
},
correctAnswer: "c"
},
{
question: "Which one of these is a JavaScript package manager?",
answers: {
a: "Node.js",
b: "TypeScript",
c: "npm"
},
correctAnswer: "c"
},
{
question: "Which tool can you use to ensure code quality?",
answers: {
a: "Angular",
b: "jQuery",
c: "RequireJS",
d: "ESLint"
},
correctAnswer: "d"
}
];
// Kick things off
buildQuiz();
// Pagination
const previousButton = document.getElementById("previous");
const nextButton = document.getElementById("next");
const slides = document.querySelectorAll(".slide");
let currentSlide = 0;
// Show the first slide
showSlide(currentSlide);
// Event listeners
submitButton.addEventListener('click', showResults);
previousButton.addEventListener("click", showPreviousSlide);
nextButton.addEventListener("click", showNextSlide);
})();
Below is the current HTML I have
<h1>Quiz on Important Facts</h1>
<div class="quiz-container">
<div id="quiz"></div>
<img id="myImg">
</div>
<button id="previous">Previous Question</button>
<button id="next">Next Question</button>
<button id="submit">Submit Quiz</button>
<div id="results"></div>
<link href="newcss1.css" rel="stylesheet" type="text/css"/>
<link rel="stylesheet" href="assets/vendor/bootstrap/css/bootstrap-reboot.rtl.min.css" type="text/css">
<script src="newjavascript.js" type="text/javascript"></script>
I am trying to create a changing text for every 3 seconds. But it seems just to run once and then it stops doing anything. My code:
HTML
<div class="output">
<h2>True Multi-Purpose Theme for
<span class="changingtext">Business</span>
and More
</h2>
</div>
JavaScript
let newText = document.querySelector('.changingtext')
setInterval(function() {
if (newText.innerHTML = 'Business'){
newText.innerHTML = 'Agencies';
}
else if (newText.innerHTML = "Agencies"){
newText.innerHTML = 'Startups';
}
else {
newText.innerHTML = 'Business';
}
}, 3000)
The problem is that you are using assignation instead of comparaison in your if
WRONG
if(newText.innerHTML = 'Business'){
CORRECT
if (newText.innerHTML === 'Business') {
let newText = document.querySelector('.changingtext')
setInterval(function() {
if (newText.innerHTML === 'Business') {
newText.innerHTML = 'Agencies';
} else if (newText.innerHTML === "Agencies") {
newText.innerHTML = 'Startups'
} else {
newText.innerHTML = 'Business'
}
}, 3000)
<div class="output">
<h2>True Multi-Purpose Theme
<be>
for
<span class="changingtext">Business</span> and More
</h2>
</div>
Also, the following could be better :
const text = document.querySelector('.changingtext')
const texts = [
'Business',
'Agencies',
'Startups',
];
function nextText() {
const actualTextIndex = texts.findIndex(x => text.innerText === x);
const newTextIndex = actualTextIndex + 1 === texts.length ? 0 : actualTextIndex + 1;
text.innerText = texts[newTextIndex];
}
setInterval(nextText, 3000)
<div class="output">
<h2>True Multi-Purpose Theme
<be>
for
<span class="changingtext">Business</span> and More
</h2>
</div>
You can improve it again by :
Creating an utility function that will work in standalone getting the selector, the time between a text change and the list of texts to loop from
Gl
Trying to display different messages inside the p element for when someone clicks on one of the three buttons. But it only displays the first message (reply) for all the buttons.
Can't see what I have done wrong...
HTML
<div class="options">
<div id="good" class="btn"></div>
<div id="idk" class="btn"></div>
<div id="bad" class="btn"></div>
</div>
JavaScript
let good = document.getElementById("good");
let idk = document.getElementById("idk");
let bad = document.getElementById("bad");
let main = document.querySelector(".main");
let reply;
document.getElementById("good"), document.getElementById("idk"), document.getElementById("bad")].forEach(option => {
option.addEventListener("click", () => {
if (good.clicked = true) {
main.style.display = "block";
reply = "Hey";
} else if (idk.clicked = true) {
main.style.display = "block";
reply = "Well yeah";
} else if (bad.clicked = true) {
main.style.display = "block";
reply = "123";
}
document.getElementById("reply").innerHTML = reply;
});
});
const good = document.getElementById("good");
const idk = document.getElementById("idk");
const bad = document.getElementById("bad");
const main = document.querySelector(".main");
const reply = document.getElementById("reply");
const messageTypes = {
good: 'Hey',
idk: 'Well yeah',
bad: '123 BAD'
};
[good, idk, bad].forEach(option => {
option.addEventListener("click", (e) => {
reply.innerHTML = messageTypes[e.target.id];
});
});
<div class="options">
<button id="good" class="btn">good</button>
<button id="idk" class="btn">idk</button>
<button id="bad" class="btn">bad</button>
</div>
<div class="main"><div>
<div id="reply"></div>
Use const for everything, create a separate message dictionary for every message and just map it against the id. You don't need to use jQuery.
If your real use case is as simple as your example, I would consider maybe using different event listeners with different logic inside them. But if you want to use the same event listener, then you can use event.target.id to know which button was clicked:
[document.getElementById("good"), document.getElementById("idk"), document.getElementById("bad")].forEach(option => {
option.addEventListener("click", (event) => {
switch (event.target.id) {
case "good":
reply = "Hey";
break;
case "idk":
reply = "Well yeah";
break;
case "bad":
reply = "123";
break;
}
main.style.display = "block";
document.getElementById("reply").innerHTML = reply;
});
});
Here you can see it working (note that I removed main.style.display = "block"; in the following example since I don't know what main is in your original code):
[document.getElementById("good"), document.getElementById("idk"), document.getElementById("bad")].forEach(option => {
option.addEventListener("click", (event) => {
switch (event.target.id) {
case "good":
reply = "Hey";
break;
case "idk":
reply = "Well yeah";
break;
case "bad":
reply = "123";
break;
}
document.getElementById("reply").innerHTML = reply;
});
});
<div class="options">
<div id="good" class="btn">good</div>
<div id="idk" class="btn">idk</div>
<div id="bad" class="btn">bad</div>
</div>
<div id="reply"/>
It could be something like that:
let good = document.getElementById("good");
let idk = document.getElementById("idk");
let bad = document.getElementById("bad");
let main = document.querySelector(".main");
let reply;
[good, idk, bad].forEach(option => {
option.addEventListener("click", (e) => {
if (e.target == good) {
main.style.display = "block";
reply = "Hey";
} else if (e.target == idk) {
main.style.display = "block";
reply = "Well yeah";
} else if (e.target == bad) {
main.style.display = "block";
reply = "123";
}
document.getElementById("reply").innerHTML = reply;
});
});
<div class="options">
<div id="good" class="btn">good</div>
<div id="idk" class="btn">idk</div>
<div id="bad" class="btn">bad</div>
</div>
<div class="main"><div>
<div id="reply"></div>
I'd be tempted to use explicit event handlers for each of the buttons rather than a generic handler that then tests all three conditions.
You can reduce the code duplication by using a function to handle the display update of the main element and the setting of reply.
Something like the following shows this in action:
let good = document.getElementById("good");
let idk = document.getElementById("idk");
let bad = document.getElementById("bad");
let main = document.querySelector(".main");
good.addEventListener("click", function(e) {
showMain("Good");
});
idk.addEventListener("click", function(e) {
showMain("Well yeah");
});
bad.addEventListener("click", function(e) {
showMain("123");
});
function showMain(replyText) {
main.style.display = "block";
document.getElementById("reply").innerHTML = replyText;
}
.main {
background-color: red;
display: none;
height: 100px;
width: 100px;
}
<button id="good">Good</button>
<button id="idk">Idk</button>
<button id="bad">Bad</button>
<div class="main"></div>
<div id="reply"></div>
You can instead, do something like this for what you want
In Pure VanillaJS
[document.getElementById("good"), document.getElementById("idk"), document.getElementById("bad")].forEach(option => {
option.addEventListener("click", (event) => {
if (event.target.id == "good") {
main.style.display = "block";
reply = "Hey";
} else if (event.target.id == "idk") {
main.style.display = "block";
reply = "Well yeah";
} else if (event.target.id == "bad") {
main.style.display = "block";
reply = "123";
}
document.getElementById("reply").innerHTML = reply;
});
});
= is used for assignments however == is used to check equality of two strings in javascript
[] ...addEventListener("click", (e) => {
if (good.id == e.target.id) {
main.style.display = "block";
reply = "Hey";
}
// and so on
document.getElementById("reply").innerHTML = reply;
});
var btn1=document.getElementById('btn1')
var btn2=document.getElementById('btn2')
var btn3=document.getElementById('btn3')
// jquery way
$('.btn').on("click",function(e){
$("#msg").html(e.target.id+" clicked");
})
// javascript way
var classname = document.getElementsByClassName("btn");
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener("click", function(e){
document.getElementById('msg').innerHTML =e.target.id+' clicked';
})
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<input type="button" id="btn1" class="btn" value="button 1">
<input type="button" id="btn2" class="btn" value="button 2">
<input type="button" id="btn3" class="btn" value="button 3">
<p id="msg"></p>
Please i want to change the temperature level in each button click. In a way to have a white arrow in a first time, two white arrow i a seconde time .... i have images withe 1 arrow, 2 arrow ext.
this my image in html :
<div id="WBR"><img src="assets/AWImages/V0.png"></div>
<button id= "HI" class="circle" >+</button>
I simulate the button click in javascript like this :
let addb = document.querySelector('#HI');
addb.addEventListener('click', () =>{
input.value = parseInt(input.value)+1;
if((input.value)<5)
{
socket.emit('Value of hum changed',input.value);
}
else
{
input.value =4;
}
});
I really appreciate ur help ;)
let addb = document.querySelector('#WBR');
let wbr = document.querySelector('#HI');
var f = document.querySelector('#f');
var Score = 0;
var win = 5;
var gameOver = false;
addb.addEventListener("click", function () {
if (!gameOver) {
Score++ ;
if (Score == win) {
gameOver = true;
addb.style.color = "green";
}
f.innerHTML = Score;
}
});
<div id="WBR"><img src="assets/AWImages/V0.png"></div>
<button id= "HI" class="circle" >+</button>
<p id="f">0</p>