How do I fill a UL with array items using jQuery? - javascript

Trying to use jQuery to place array values into a ul of radio buttons.
HTML
<div class="quizWindow">
<h1>The Bridge Of Death</h1>
<div id="question"></div>
<form>
<ul id = "choices">
</ul>
</form>
<div id = "quizMessage"></div>
<div id = "result"></div>
<div id = "nextButton"><span>Start Quiz</span></div>
<br>
</div>
JS
var allQuestions = [{question: "What, is your name?", choices: ["Sir Lancelot the brave", "Sir Galahad the brave", "Sir not appearing in this film"], correctAnswer: 1}, {question: "What, is your quest?", choices: ["To seek the holy grail", "To dream the impossible dream", "To get back on the horse"], correctAnswer: 1 }, {question: "What is the airspeed velocity of an unladen swallow?", choices: ["16mph", "I don't know that!", "What do you mean; an african or a european swallow?"], correctAnswer: 3}];
$(document).ready(function () {
//Start Quiz, show first set of questions
$('#nextButton').click(function () {
$('#question').text(allQuestions[0].question);
for (var i = 0; i <= allQuestions.length; i++) {
$.each(allQuestions, function(i, question) {
var $ul = $('<ul/>'); //make a new ul for this question
//iterate through each choice for this question
$.each(question.choices, function (i, choices) {
//add the choice to the ul
$ul.append('<li><label><input type="radio" name="question' + i + '" value="' + choices + '"> ' + choices + '</label></li>');
});
//add the new ul to the form
$('.choices').append($ul);
});
}
});
});
I've got the question showing up in the HTML, but none of the choices below it. I think this is a problem of my HTML formatting in the jQuery but I'm not seeing it.

You can easily use $.each to iterate through objects and arrays. Please note I've changed the name for each input to be 'question'+question number. This is because you obviously can't have multiple questions that all have the same name.
//iterate through each question
$.each(allQuestions, function(i, question){
var $ul = $('<ul/>'); //make a new ul for this question
//iterate through each choice for this question
$.each(question.choices, function(ii, choice){
//add the choice to the ul
$ul.append('<li><label><input type="radio" name="question'+i+'" value="'+choice+'"> '+choice+'</label></li>');
});
//add the new ul to the form
$('.choices').append($ul)
});

Yes you will need to loop. Try something like this.
var $ul = $('ul.yourUl');
for(var i = 0; i < allQuestions.length; i++) {
var $li = $("<li></li>"); //Do whatever is needed to make this li
$ul.append($li);
}

Related

How to display 5 questions from a JavaScript array at the same time in HTML?

I am developing a page for a quiz or a test with lots of questions and in my HTML its only showing one question at a time from the questions array I have created, but I need to show 5 questions at a time, and when next button is clicked it needs to show the next set of 5 questions. How can I do this, please help.
let questions = [{
numb: 1,
question: "What does HTML stand for?",
answer: "Hyper Text Markup Language",
options: [
"Hyper Text Preprocessor",
"Hyper Text Markup Language",
"Hyper Text Multiple Language",
"Hyper Tool Multi Language"
]
},
{
numb: 2,
question: "What does CSS stand for?",
answer: "Cascading Style Sheet",
options: [
"Common Style Sheet",
"Colorful Style Sheet",
"Computer Style Sheet",
"Cascading Style Sheet"
]
},
{
numb: 3,
question: "What does PHP stand for?",
answer: "Hypertext Preprocessor",
options: [
"Hypertext Preprocessor",
"Hypertext Programming",
"Hypertext Preprogramming",
"Hometext Preprocessor"
]
},
{
numb: 4,
question: "What does SQL stand for?",
answer: "Structured Query Language",
options: [
"Stylish Question Language",
"Stylesheet Query Language",
"Statement Question Language",
"Structured Query Language"
]
},
{
numb: 5,
question: "What does XML stand for?",
answer: "eXtensible Markup Language",
options: [
"eXtensible Markup Language",
"eXecutable Multiple Language",
"eXTra Multi-Program Language",
"eXamine Multiple Language"
]
}]
//for questions
//selecting all required elements
const start_btn = document.querySelector(".start_btn button");
const info_box = document.querySelector(".info_box");
const exit_btn = info_box.querySelector(".buttons .quit");
const continue_btn = info_box.querySelector(".buttons .restart");
const quiz_box = document.querySelector(".quiz_box");
const result_box = document.querySelector(".result_box");
const option_list = document.querySelector(".option_list");
const time_line = document.querySelector("header .time_line");
const timeText = document.querySelector(".timer .time_left_txt");
const timeCount = document.querySelector(".timer .timer_sec");
// if startQuiz button clicked
start_btn.onclick = () => {
// info_box.classList.add("activeInfo"); //show info box
info_box.classList.remove("activeInfo"); //hide info box
quiz_box.classList.add("activeQuiz"); //show quiz box
showQuetions(0); //calling showQestions function
queCounter(1); //passing 1 parameter to queCounter
startTimer(120); //calling startTimer function
startTimerLine(0); //calling startTimerLine function
}
let timeValue = 15;
let que_count = 0;
let que_numb = 1;
let userScore = 0;
let counter;
let counterLine;
let widthValue = 0;
const restart_quiz = result_box.querySelector(".buttons .restart");
const quit_quiz = result_box.querySelector(".buttons .quit");
// if restartQuiz button clicked
restart_quiz.onclick = () => {
quiz_box.classList.add("activeQuiz"); //show quiz box
result_box.classList.remove("activeResult"); //hide result box
timeValue = 15;
que_count = 0;
que_numb = 1;
userScore = 0;
widthValue = 0;
showQuetions(que_count); //calling showQestions function
queCounter(que_numb); //passing que_numb value to queCounter
clearInterval(counter); //clear counter
clearInterval(counterLine); //clear counterLine
startTimer(timeValue); //calling startTimer function
startTimerLine(widthValue); //calling startTimerLine function
timeText.textContent = "Time Left"; //change the text of timeText to Time Left
next_btn.classList.remove("show"); //hide the next button
}
// if quitQuiz button clicked
quit_quiz.onclick = () => {
window.location.reload(); //reload the current window
}
const next_btn = document.querySelector("footer .next_btn");
const bottom_ques_counter = document.querySelector("footer .total_que");
// if Next Que button clicked
next_btn.onclick = () => {
if (que_count < questions.length - 1) { //if question count is less than total question length
que_count++; //increment the que_count value
que_numb++; //increment the que_numb value
showQuetions(que_count); //calling showQestions function
queCounter(que_numb); //passing que_numb value to queCounter
clearInterval(counter); //clear counter
clearInterval(counterLine); //clear counterLine
startTimer(timeValue); //calling startTimer function
startTimerLine(widthValue); //calling startTimerLine function
timeText.textContent = "Time Left"; //change the timeText to Time Left
next_btn.classList.remove("show"); //hide the next button
} else {
clearInterval(counter); //clear counter
clearInterval(counterLine); //clear counterLine
showResult(); //calling showResult function
}
}
// getting questions and options from array
function showQuetions(index) {
const que_text = document.querySelector(".que_text");
//creating a new span and div tag for question and option and passing the value using array index
let que_tag = '<span>' + questions[index].numb + ". " + questions[index].question + '</span>';
let option_tag = '<div class="option"><span>' + questions[index].options[0] + '</span></div>' +
'<div class="option"><span>' + questions[index].options[1] + '</span></div>' +
'<div class="option"><span>' + questions[index].options[2] + '</span></div>' +
'<div class="option"><span>' + questions[index].options[3] + '</span></div>';
que_text.innerHTML = que_tag; //adding new span tag inside que_tag
option_list.innerHTML = option_tag; //adding new div tag inside option_tag
const option = option_list.querySelectorAll(".option");
// set onclick attribute to all available options
for (i = 0; i < option.length; i++) {
option[i].setAttribute("onclick", "optionSelected(this)");
}
}
// creating the new div tags which for icons
let tickIconTag = '<div class="icon tick"><i class="fas fa-check"></i></div>';
let crossIconTag = '<div class="icon cross"><i class="fas fa-times"></i></div>';
//if user clicked on option
function optionSelected(answer) {
clearInterval(counter); //clear counter
clearInterval(counterLine); //clear counterLine
let userAns = answer.textContent; //getting user selected option
let correcAns = questions[que_count].answer; //getting correct answer from array
const allOptions = option_list.children.length; //getting all option items
if (userAns == correcAns) { //if user selected option is equal to array's correct answer
userScore += 1; //upgrading score value with 1
answer.classList.add("correct"); //adding green color to correct selected option
answer.insertAdjacentHTML("beforeend", tickIconTag); //adding tick icon to correct selected option
console.log("Correct Answer");
console.log("Your correct answers = " + userScore);
} else {
answer.classList.add("incorrect"); //adding red color to correct selected option
answer.insertAdjacentHTML("beforeend", crossIconTag); //adding cross icon to correct selected option
console.log("Wrong Answer");
for (i = 0; i < allOptions; i++) {
if (option_list.children[i].textContent == correcAns) { //if there is an option which is matched to an array answer
option_list.children[i].setAttribute("class", "option correct"); //adding green color to matched option
option_list.children[i].insertAdjacentHTML("beforeend", tickIconTag); //adding tick icon to matched option
console.log("Auto selected correct answer.");
}
}
}
for (i = 0; i < allOptions; i++) {
option_list.children[i].classList.add("disabled"); //once user select an option then disabled all options
}
next_btn.classList.add("show"); //show the next button if user selected any option
}
function showResult() {
info_box.classList.remove("activeInfo"); //hide info box
quiz_box.classList.remove("activeQuiz"); //hide quiz box
result_box.classList.add("activeResult"); //show result box
const scoreText = result_box.querySelector(".score_text");
if (userScore > 3) { // if user scored more than 3
//creating a new span tag and passing the user score number and total question number
let scoreTag = '<span>and congrats! 🎉, You got <p>' + userScore + '</p> out of <p>' + questions.length + '</p></span>';
scoreText.innerHTML = scoreTag; //adding new span tag inside score_Text
} else if (userScore > 1) { // if user scored more than 1
let scoreTag = '<span>and nice 😎, You got <p>' + userScore + '</p> out of <p>' + questions.length + '</p></span>';
scoreText.innerHTML = scoreTag;
} else { // if user scored less than 1
let scoreTag = '<span>and sorry 😐, You got only <p>' + userScore + '</p> out of <p>' + questions.length + '</p></span>';
scoreText.innerHTML = scoreTag;
}
}
function startTimer(time) {
counter = setInterval(timer, 1000);
function timer() {
timeCount.textContent = time; //changing the value of timeCount with time value
time--; //decrement the time value
if (time < 9) { //if timer is less than 9
let addZero = timeCount.textContent;
timeCount.textContent = "0" + addZero; //add a 0 before time value
}
if (time < 0) { //if timer is less than 0
clearInterval(counter); //clear counter
timeText.textContent = "Time Off"; //change the time text to time off
const allOptions = option_list.children.length; //getting all option items
let correcAns = questions[que_count].answer; //getting correct answer from array
for (i = 0; i < allOptions; i++) {
if (option_list.children[i].textContent == correcAns) { //if there is an option which is matched to an array answer
option_list.children[i].setAttribute("class", "option correct"); //adding green color to matched option
option_list.children[i].insertAdjacentHTML("beforeend", tickIconTag); //adding tick icon to matched option
console.log("Time Off: Auto selected correct answer.");
}
}
for (i = 0; i < allOptions; i++) {
option_list.children[i].classList.add("disabled"); //once user select an option then disabled all options
}
next_btn.classList.add("show"); //show the next button if user selected any option
}
}
}
function startTimerLine(time) {
counterLine = setInterval(timer, 29);
function timer() {
time += 1; //upgrading time value with 1
time_line.style.width = time + "px"; //increasing width of time_line with px by time value
if (time > 549) { //if time value is greater than 549
clearInterval(counterLine); //clear counterLine
}
}
}
function queCounter(index) {
//creating a new span tag and passing the question number and total question
let totalQueCounTag = '<span><p>' + index + '</p> of <p>' + questions.length + '</p> Questions</span>';
bottom_ques_counter.innerHTML = totalQueCounTag; //adding new span tag inside bottom_ques_counter
}
<!-- questions -->
<div class="start_btn"><button>Start Answering</button></div>
<!-- Info Box -->
<div class="info_box">
<div class="buttons">
<button class="quit">Exit Quiz</button>
<button class="restart">Continue</button>
</div>
</div>
<!-- Quiz Box -->
<div class="quiz_box">
<header>
<div class="title">Questions</div>
<div class="timer">
<div class="time_left_txt">Time Left</div>
<div class="timer_sec">15</div>
</div>
<div class="time_line"></div>
</header>
<section>
<div class="que_text">
</div>
<div class="option_list">
</div>
</section>
<!-- footer of Quiz Box -->
<footer>
<div class="total_que">
<!-- Here I've inserted Question Count Number from JavaScript -->
</div>
<button class="next_btn">Next Que</button>
</footer>
</div>
<!-- Result Box -->
<div class="result_box">
<div class="icon">
<i class="fas fa-crown"></i>
</div>
<div class="complete_text">You've completed the Quiz!</div>
<div class="score_text">
<!-- Here I've inserted Score Result from JavaScript -->
</div>
<div class="buttons">
<button class="restart">Replay Quiz</button>
<button class="quit">Quit Quiz</button>
</div>
</div>
EDIT: Here is a repl which shows what you wanted with Next and Previous buttons
Too much was built so rigid around that entire construct.. so editing your code was hard.. instead I just made a dynamic question display setup(n controls the amount of questions displayed because displayQuestion displays all questions that is given with the arr argument)
Now for the step by step walkthrough
There are 3 main functions:
The event listener of startBtn: the first line inside this code simply changes the text displayed from the startButton, not all that important.. right below that is an important variable n which is used in a filter later down in such a way that n CONTROLS the amount of questions that will be displayed at one time
The displayQuestions function: this function takes in 2 arguments; arr and questionBar. arr is the array of questions given(remember it's the event listener that gives an intelligently filtered array of questions). it iterates through each question item, makes an element(which would encompass the question and its options), a function(which would be click listeners for all the different options of the question; and stop listening from all options when one is selected) and then it iterates through the options to append the options to the parent question and add the specialised listener function to each option
The displayResults function: this takes in the results object(in its first argument) and prints the main results to given element(in its second argument)
var questionBar=document.getElementById('questions')
var startBtn=document.getElementById('start')
startBtn.addEventListener('click', async function(){
questionBar.innerHTML="" //important to prevent overlap(move this line to the beginning of the displayQuestions to ONLY show 5 questions at a time on the whole document)
startBtn.innerText="Restart Questions"
var n=5 //change this number to change the amount of questions shown
var results={correct:0,totalPossible:0}
for(var i=0;i<questions.length;i+=n){
var result=await displayQuestions(
questions.filter((a,j)=>j>=i&&j<i+n),
questionBar
)
Object.keys(result).forEach(a=>{
if(a=="correct"){results.correct+=result.correct}
else if(a=="totalPossible"){results.totalPossible+=result.totalPossible}
else{results[a]=result[a]}
})
}
displayResults(results,questionBar)
})
async function displayQuestions(arr,questionBar){
var finished=arr.length //a test for if all questions answered
var answered=0; var correct=0
var corrections={}
arr.forEach(a=>{
var question=document.createElement('div')
question.className="question" //for css to change looks
var options=[] //will become an array of elements(that have the question options) in order to remove event listener from them
//the function below handles when a question option is selected and removes listening when an answer is selected(one can only answer once)
function listen(ev){
var answer=ev.path[0].innerText
if(answer==a.answer){
question.className="correct";correct++;answered++
ev.path[0].className="selected"
corrections[a.numb]={
correct:true, userAnswer:answer, correctAnswer:a.answer
}
}
else{
question.className="wrong";answered++
ev.path[0].className="selected"
corrections[a.numb]={
correct:false, userAnswer:answer, correctAnswer:a.answer
}
}
options.forEach(c=>{c.removeEventListener('click',listen)})
}
var title=document.createElement('span')
title.classList.add('title') //for css to change looks
title.innerText=`(${a.numb}) ${a.question}`
question.appendChild(title)
a.options.forEach(b=>{
var option=document.createElement('div')
option.className="option" //for css to change looks
option.innerText=b
option.addEventListener('click',listen)
options.push(option)
question.appendChild(option)
})
questionBar.appendChild(question)
})
var p=new Promise(results=>{
var i=setInterval(()=>{
if(answered==finished){
clearInterval(i) //the timeout INSIDE the interval ensures that I can fix the time that you have to look at the final display of what was right and wrong before the results function is run
//it's just a personal preference because it looks glitchy when the question immediately goes into results
setTimeout(()=>{
corrections.correct=correct
corrections.totalPossible=finished
results(corrections)
},1000)
}
},0)
})
return await p
}
function displayResults(corrections,elem){
//the corrections object has A LOT of data you can use in MANY ways
console.log(corrections)
var correct=corrections.correct
var totalPossible=corrections.totalPossible
elem.innerText=`You got ${correct} of ${totalPossible}`
}
.wrong {
background-color: red;
border-radius: 5px;
margin: 20px;
}
.correct {
background-color: lightgreen;
border-radius: 5px;
margin: 20px;
}
.question{
background-color: lightblue;
border-radius: 5px;
margin: 20px;
}
.title{
font-weight: bold;
font-family: Verdana;
}
.option{
font-family: Courier, sans-serif;
margin: 5px;
}
.selected{
font-family: Courier, sans-serif;
margin: 5px;
background-color: orange;
}
<div class="start_btn">
<button id="start">Start Questions</button>
</div>
<div id="questions"></div>
<script>
//btw all numb values should be unique.. I'm counting on that xD
let questions = [{
numb: 1,
question: "What does HTML stand for?",
answer: "Hyper Text Markup Language",
options: [
"Hyper Text Preprocessor",
"Hyper Text Markup Language",
"Hyper Text Multiple Language",
"Hyper Tool Multi Language"
]
},
{
numb: 2,
question: "What does CSS stand for?",
answer: "Cascading Style Sheet",
options: [
"Common Style Sheet",
"Colorful Style Sheet",
"Computer Style Sheet",
"Cascading Style Sheet"
]
},
{
numb: 3,
question: "What does PHP stand for?",
answer: "Hypertext Preprocessor",
options: [
"Hypertext Preprocessor",
"Hypertext Programming",
"Hypertext Preprogramming",
"Hometext Preprocessor"
]
},
{
numb: 4,
question: "What does SQL stand for?",
answer: "Structured Query Language",
options: [
"Stylish Question Language",
"Stylesheet Query Language",
"Statement Question Language",
"Structured Query Language"
]
},
{
numb: 5,
question: "What does XML stand for?",
answer: "eXtensible Markup Language",
options: [
"eXtensible Markup Language",
"eXecutable Multiple Language",
"eXTra Multi-Program Language",
"eXamine Multiple Language"
]
},
{
numb: 6,
question: "Why did the cow cross the road",
answer: "There was no road, it was grass",
options: [
"idk LOL",
"COWS CAN'T SWIM",
"There was no road, it was grass",
"Bruh pls, NEXT"
]
},
{
numb: 7,
question: "How to select element with 2 classes(CSS)",
answer: "Chain dots like: .a.b",
options: [
"Chain dots like: .a.b",
"It's impossible",
"Sequence dots like: .a .b",
"explore the universe, then come back"
]
},
{
numb: 8,
question: "What is 9+10?",
answer: "Nineteen",
options: [
"Twenty one",
"nothing at all, irrelevant",
"IDK, YOU TELL ME",
"Nineteen"
]
},
{
numb: 9,
question: "How does a C linked list work?",
answer: "structs and pointer logic",
options: [
"high level javascript magic",
"some random module",
"that doesn't exist",
"structs and pointer logic"
]
},
{
numb: 10,
question: "Is light a particle?",
answer: "It behaves like a particle AND a wave",
options: [
"Affirmitave",
"Nope, not even close",
"It behaves like a particle AND a wave",
"It's a unicorn"
]
},
{
numb: 11,
question: "What is a bit?",
answer: "A binary digit",
options: [
"A binary digit",
"BEEP BOOP",
"69",
"idk smh xD"
]
}
]
</script>

Replacing radio button with "selected" in JavaScript

I'm trying to make a quiz powered by jQuery (and maybe JSON), with the values stored in a database. It works fine so far, but I'd like to hide the radio buttons (CSS: display: none) and make each question look like a button (much easier to select than a tiny radio button).
However, when I do this, the following JavaScript doesn't work, and the quiz isn't scored.
var imgpath = "/images/sections/test/";
var jsonpath = "/2b/inc/pages/quiz-php/json/";
var jsonfile = "key";
$(document).ready(function(){
//Make sure radio buttons are not disabled or checked (helpful when refreshing)
$("input[type='radio']").attr("disabled", false);
$("input[type='radio']").attr("checked", false);
$(".submit").click(function(e){
e.preventDefault();
//Check the quiz results
checkQuiz();
});
//Build the json filename
jsonfile = $("#quiz").attr("rel")+".php";
});
//Load json file
function getData(update){
$.getJSON(jsonpath+jsonfile, function(json){
//Execute the callback
update(json);
}).error(function(){alert("error");});
}
function checkQuiz(){
$(".submit").remove();
getData(function(data){
var ans = data.key;
var result = {};
$(".Question").each(function(){
//Get the question id
var _q = $(this).attr("id");
//Get the selected answer class
var _a = $("#"+_q+" input:checked").closest("li").attr("class");
//Add the values to the result object
result[_q] = _a;
//Compare the selected answer with the correct answer
if(ans[_q]==_a){
$(this).addClass("correct");
}else{
$(this).addClass("wrong");
}
});
//Build the feedback
var fdbck = "You got "+$(".correct").length+" out of "+$(".Question").length+" correct. "
if($(".correct").length==0){
fdbck += "Better luck next time.";
}else if($(".correct").length>$(".Question").length/2){
fdbck += "Good job!";
}else{
fdbck += "Not bad.";
}
$(".feedback").text(fdbck);
$(".feedback").show();
});
}
So I wondered if there's some way to record scores besides a radio button. I created a JSFiddle # http://jsfiddle.net/9j7fz99w/6/ to illustrate how I'm using jQuery and CSS to style correct and incorrect answers. Is there a way to modify the code above to similarly recognize correct questions based on their "selection," rather than a radio button?
Just a small example using a JS questions Array with Objects
var $quizEl = $("#quizEl");
var $submit = $("#submit");
var quiz = [
{ // obj
"Q" : "What color is the Sun?",
"A" : ["Red", "Black", "Yellow"],
"C" : 2
},{
"Q" : "What color is an Elephant?",
"A" : ["Gray", "Blue", "Yellow"],
"C" : 0 // zero indexed!
},{
"Q" : "What color is the Sea?",
"A" : ["Fuchsia", "Blue", "Gold"],
"C" : 1
}
];
var qNum = quiz.length;
// FUNCTION THAT CREATES AND APPENDS AN `UL` TO `DIV #quizEl`
function generateQuestion( obj, idx ) {
var html = "<h2>"+ obj.Q +"</h2><ul>";
for (var i=0; i<obj.A.length; i++) {
html += "<li>"+
"<label>"+
"<input type='radio' name='"+ idx +"' value='"+i+"'>"+
obj.A[i] +"</label>"+
"</li>";
}
$quizEl.append( html+"</ul>" );
}
// GENERATE ALL QUESTIONS:
for(var i=0; i<qNum; i++) {
generateQuestion( quiz[i], i ); // quiz[i] is the {QAC} object
}
$quizEl.on("change", ":radio", function(){ // Record User choice (U property)
quiz[this.name].U = this.value; // set 0,1,2 to the new U property {QACU}
});
$submit.on("click", function(e){
e.preventDefault();
console.log( quiz ); // To test how it looks
// Check if user answered them all:
for(var i=0; i<qNum;i++){
if(!quiz[i].hasOwnProperty("U")){ // User did not answered if "U" property doesn't exists
return alert("Please,\nanswer the question "+ (i+1) +":\n"+ quiz[i].Q );
}else{ // Add classes...
$("ul").eq(i).find(":checked").closest("li")
.addClass( +quiz[i].U === quiz[i].C ? "correct":"wrong");
}
}
// Finally colour them!
$(".correct").css({background:"green"});
$(".wrong").css({background:"red"});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="quizEl"></div>
<input id="submit" type="submit">

Looping through array using a button

Ok, in essence I want to create a short quiz that has a next and previous button. I want to loop through two arrays, questions and choices, and have a score at the end. I have read chapters on the DOM and Events and it is just not clicking apparently.
Really I need a little bit of code that shows a concrete example of how to manipulate the DOM. What I have so far are only the arrays, and a function declaring that x is in fact getting my element by id. haha.
Sorry I don't have more code to give. I tried to attach the id to a paragraph, and then get it by it's id and document.write the array, but that replaces the button. If you run the code below you'll see what I'm saying.
<!DOCTYPE html>
<html>
<head>
<title>Bom</title>
</head>
<body>
<input type="button" value="Iterate" id="myButton" onclick="iter_onclick()">
<p id="qArray">Some Text</p>
<script>
var qArray = ["Who is my dog?", "who is the prez?", "Who is my girlfriend?", "Who am I?"];
var cArray = [["Bill","Billy", "Arnold", "Tyler"],["Oz"," Buffon","Tupac","Amy"],["Tony Blair","Brack Osama","Barack Obama","Little Arlo"],["Emma Stone","Tony the Tiger","","The Smurf Girl"]];
function iter_onclick () {
var x = document.getElementById("qArray");
document.write("Hello World");
}
</script>
</body>
</html>`
Like I said, this is my first attempt at truly manipulating the DOM, and I know what I want to do. I just don't know how to do it. I am understanding all the syntax and events and objects and such. But, I'm not really sure how to apply it. Also, no Jquery. I want to know how to create applications with Javascript and then work my way into Jquery. Thanks people.
This will loop through your questions, hope this helps you to proceed.
var qArray = ["Who is my dog?",
"who is the prez?",
"Who is my girlfriend?",
"Who am I?"];
var cArray = [
["Bill", "Billy", "Arnold", "Tyler"],
["Oz", " Buffon", "Tupac", "Amy"],
["Tony Blair", "Brack Osama", "Barack Obama", "Little Arlo"],
["Emma Stone", "Tony the Tiger", "Amy Dahlquist", "The Smurf Girl"]
];
var index = 0;
function iter_onclick() {
//if this is the last question hide and displays quiz ends
if (index >= qArray.length) {
document.getElementById('qArray').innerHTML = '<div>Quiz End, Thank you</div>'
document.getElementById('myButton').style.visibility = 'hidden ';
return false;
}
var html = ' <div> ' + qArray[index] + ' </div> <div>';
for (var i = 0; i < cArray[index].length; i++) {
html += '<label><input type="radio" name="ans" value="'
+ cArray[index][i] + '"/ > ' + cArray[index][i] + ' </label>';
}
html += '</div > ';
document.getElementById('qArray').innerHTML = html;
index++;
}
Here's a very basic example you can work from. This modifies the existing DOM items. You cannot use document.write() on a document that is already loaded or it will clear everything you have and start over and it's not the most efficient way to put content into the DOM.
This example has a number of fields on the page, it loads a question and then checks the answer when you press the next button.
HTML:
<div id="question"></div>
<input id="answer" type="text"><br><br>
<button id="next">Next</button> <br><br><br>
Number Correct So Far: <span id="numCorrect">0</span>
Javascript (in script tag):
var qArray = ["Who is my dog?", "who is the prez?", "Who is my girlfriend?", "Who am I?"];
var cArray = [["Bill","Billy", "Arnold", "Tyler"],["Oz"," Buffon","Tupac","Amy"],["Tony Blair","Brack Osama","Barack Obama","Little Arlo"],["Emma Stone","Tony the Tiger","Amy Dahlquist","The Smurf Girl"]];
var questionNum = -1;
var numCorrect = 0;
function loadQuestion() {
++questionNum;
if (questionNum >= qArray.length) {
alert("all questions are done");
} else {
document.getElementById("question").innerHTML = qArray[questionNum];
document.getElementById("answer").value = "";
}
}
loadQuestion();
function checkAnswer() {
var answer = document.getElementById("answer").value.toLowerCase();
var allowedAnswers = cArray[questionNum];
for (var i = 0; i < allowedAnswers.length; i++) {
if (allowedAnswers[i].toLowerCase() == answer) {
return true;
}
}
return false;
}
document.getElementById("next").addEventListener("click", function(e) {
if (checkAnswer()) {
++numCorrect;
document.getElementById("numCorrect").innerHTML = numCorrect;
loadQuestion();
} else {
alert("Answer is not correct");
}
});
Working demo: http://jsfiddle.net/jfriend00/gX2Rm/

Understanding nodes and how to append

I've been working on a project that some other developers had started and I'm trying to understand the code while also completing the project. Currently what I have is some json with links and a url text (pretty much a quick description), what I need to do is on a button click I want to display each of the links with their correct text and make it a clickable link. The way this needs to be done is using nodes which I'm not 100% knowledgeable on. If I need to explain this more please let me know also I have provided an example of what I'm currently working with. Thanks
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>JavaScript And JSON</title>
</head>
<body bgcolor='#CED3F3'>
<button onclick="appendUrl()">Append</button><br>
<br><script id = "i">
function category()
//adding function with button click removes html page styling?
{
var category = {
"content": [
{
"links": "basic information",
"urlText": "Basis Information System",
"urlDesc": "portal for technology development, people search, a keyword search ."
},
{
"links": "http://site.com",
"urlText": "Net",
"urlDesc": "the entry page example"
},
{
"links": "http://newsgroups.com",
"urlText": "Newsgroups",
"urlDesc": "information internal newsgroups, usage, tools, statistics, netiquette"
},
{
"links": "http://site2.com",
"urlText": "Another site",
"urlDesc": "community for transfer of knowledge and technical information"
},
{
"links": "http://news.com",
"urlText": " some news",
"urlDesc": "place with news"
}
]
}
</script>
<script>
function appendUrl()
{
//there needs to be a loop here?
var link = "needs to loop through links?"
var node=document.createElement("LI");
var nodeA=document.createElement("A");
var textnode=document.createTextNode();
node.appendChild(nodeA);
nodeA.appendChild(textnode);
nodeA.href=(link);
nodeA.target="_blank";
document.getElementById("i").appendChild(node);
}
</script>
</body>
</html>
First you are going to need your category function to actually return the json data, otherwise it is of no use to anyone.
function category()
{
var category = {
"content": [
...
]
}
return category;
}
Then you can simply loop over the content array in the category object like this:
var content = category().content;
for (var i = 0; i < content.length; i++) {
var item = content[i];
var link = item.links;
var node=document.createElement("LI");
var nodeA=document.createElement("A");
var textnode=document.createTextNode(item.urlText);
node.appendChild(nodeA);
nodeA.appendChild(textnode);
nodeA.href=(link);
nodeA.target="_blank";
document.getElementById("i").appendChild(node);
}
However, if you're going to be creating list items in the markup, you are going to want to add them to a ul element, so you should have a ul somewhere in your markup like this:
<ul id="i"></ul>
And remove the id="i" from the script tag. You don't want to add the list items to the script.
This is the type of stuff jquery makes very easy to accomplish - if you can use it in your project.
var ul = $("<ul></ul">);
for(var i in category.content){
var li = $("<li></li>");
var a = $("<a href='" + category.content[i].links + "'>" + category.content[i].urlText + "</a>");
li.append(a);
ul.append(li);
}
containerDiv.append(ul);
In your example you also make list items children of a script tag. Not sure what your goal was there but I would have a plain div.
If you really have to do it in plain javascript:
var containerDiv = document.getElementById("parent");
var ul = document.createElement("ul");
for(var i in category.content){
var li = document.createElement("li");
var a = document.createElement("a");
a.href = category.content[i].links;
a.innerHTML = category.content[i].urlText;
li.appendChild(a);
ul.appendChild(li);
}
containerDiv.appendChild(ul);
A fiddle here

Changing a div's id in order to show/hide

My old code looked like this:
function unhide(rad) {
var id = "answer" + rad.id.replace("-", "");
var answer = document.getElementById(id);
if (answer) {
var current = document.getElementById(currentShown);
if (current) current.className = "hidden";
currentShown = id;
answer.className = "unhidden";
}
}
When my radio button was clicked:
<input class="editable" type="radio" name="q1" id="q1-a" onclick="unhide(this); scoreIncrement(this);"/>John
It would unhide this div:
<div id="answerq1a" class="hidden">
<p>Your answer is correct, John is 6ft2.</p>
</div>
But now, my radio button must look like this:
<input class="editable" type="radio" name="q1" id="untitled-region-1" onclick="unhide(this); scoreIncrement(this);"/>John
and my div that I want to unhide has the same id, but as they are unique, it replaces the 1 with the next number up. In my case it is 4 id's down so the id would be "untitled-region-5" for the new id, as follows:
<div id="untitled-region-5" class="hidden">
<p>Your answer is correct, John is 6ft2.</p>
</div>
So how can I change this code, to grab the new id "untitled-region-5" and minus 4 from it to fix it to the radio button with the new id's?
function unhide(rad) {
var id = "answer" + rad.id.replace("-", "");
var answer = document.getElementById(id);
if (answer) {
var current = document.getElementById(currentShown);
if (current) current.className = "hidden";
currentShown = id;
answer.className = "unhidden";
}
}
I am going along this sort of track:
function unhide2(rad) {
var id = $("div").attr('id').replace(/untitled-region-/, 'untitled-region-');
var untitled-region = document.getElementById(id);
if (untitled-region) {
var current = document.getElementById(currentShown);
if (current) current.className = "hidden";
currentShown = id;
untitled-region.className = "unhidden";
}
}
But I don't know how to replace the last digit on the id with "digit-4".
You've tagged this with jQuery, so I'll give you the jQuery answer.
The right way to solve this is not to mash about with id's, but to link the radio, and it's associated div some other way, and IMO the best way is using a data- attribute.
<input class="editable" type="radio"
name="q1" id="q1-a" data-answerId="untitled-region-5"/>John
Then your javascript becomes easy-as:
$('.editable').click(function(){
$('#' + currentShown).removeClass('unhidden').addClass('hidden');
var answerId = $(this).data('answerId');
$('#' + answerId).removeClass('hidden').addClass('unhidden');
});
Although I urge you to do away with the unhidden, hidden confusion and just use .show() and .hide()!

Categories

Resources