how to use forEach() on nested objects in an array - javascript

I'm working on a browser quiz project. I have made an array of objects that has the question choices nested in a further object. I'm struggling to figure out how to compare the users choice of the 4 options to the correct answer in the answers array.
I'm stuck because I don't know how to use for each on nested objects inside an array.
const list = document.createElement('ol');
const li1 = document.createElement('li');
const li2 = document.createElement('li');
const li3 = document.createElement('li');
const li4 = document.createElement('li');
const choices = document.querySelector('.choices');
choices.appendChild(list);
list.appendChild(li1);
list.appendChild(li2);
list.appendChild(li3);
list.appendChild(li4);
const possibleAnswers = ['1', '2', '3', '4', '5', '6', '7'];
const questionPool = [
{
questionOne:
{
answers:
{
answerOne: li1,
answerTwo: li2,
answerThree: li3,
answerFour: li4
}
}
},
{
questionTwo:
{
answers:
{
answerOne: li1,
answerTwo: li2,
answerThree: li3,
answerFour: li4
}
}
},
{
questionThree:
{
answers:
{
answerOne: li1,
answerTwo: li2,
answerThree: li3,
answerFour: li4
}
}
},
{
questionFour:
{
answers:
{
answerOne: li1,
answerTwo: li2,
answerThree: li3,
answerFour: li4
}
}
},
{
questionFive:
{
answers:
{
answerOne: li1,
answerTwo: li2,
answerThree: li3,
answerFour: li4
}
}
},
{
questionSix:
{
answers:
{
answerOne: li1,
answerTwo: li2,
answerThree: li3,
answerFour: li4
}
}
},
{
questionSeven:
{
answers:
{
answerOne: li1,
answerTwo: li2,
answerThree: li3,
answerFour: li4
}
}
}
];

If I understood your question correctly I think this answer might help you;
You have to change the structure of your object to make it universal.
You can go through your object array in which each object refers to the object of the 4 answers.
Loop to access the 4 possible answers.
This is how I would do it:
var list = document.createElement("ol");
var li1 = document.createElement("li");
var li2 = document.createElement("li");
var li3 = document.createElement("li");
var li4 = document.createElement("li");
let choices = document.querySelector(".choices")
choices.appendChild(list)
list.appendChild(li1)
list.appendChild(li2)
list.appendChild(li3)
list.appendChild(li4)
let questionPool = [
{
answers: {
1: li1,
2: li2,
3: li3,
4: li4
}
},
{
answers: {
1: li1,
2: li2,
3: li3,
4: li4
}
},
{
answers: {
1: li1,
2: li2,
3: li3,
4: li4
}
}
];
questionPool.forEach(element => {
for(const item in element.answers){
//here you have access to the 4 li
console.log(element.answers[item]);
}
});

I tried to refactor your code beacause most of it was repetitions for no reason, more details in the comments :
const questionEl = document.createElement('span')
const list = document.createElement("ol");
const nextBtn = document.createElement('button')
const choicesEl = document.querySelector(".choices")
nextBtn.textContent = 'Next'
choicesEl.appendChild(questionEl)
choicesEl.appendChild(list)
choicesEl.appendChild(nextBtn)
// Store you list elements by span (text of the answer) and radio (input field)
const listElements = Array.from({ length: 4 }).map(i => {
const li = document.createElement('li')
const radio = document.createElement('input')
const span = document.createElement('span')
radio.type = 'radio'
radio.name = 'quiz-radio'
li.appendChild(radio)
li.appendChild(span)
list.appendChild(li)
// for convenience
span.onclick = () => radio.click()
return { radio, span }
})
// use arrays instead of objects
const questionsPool = [
{
question: 'What is the formula for water ?',
right: 0,
answers: [
'H2O',
'NH3',
'CO2',
'C6H12O6',
]
}, {
question: 'What color is the sky ?',
right: 1,
answers: [
'blue',
'skyblue',
'lightblue',
'navyblue',
]
}
]
let score = 0
let questionIndex = 0
// update the texts in the spans
const updateQuestion = () => {
const { question, answers } = questionsPool[questionIndex]
questionEl.textContent = question
for (let i = 0; i < 4; i++)
listElements[i].span.textContent = answers[i]
}
// inital rendering
updateQuestion()
nextBtn.onclick = () => {
// if the user selected the right answer : increment his score
if (listElements[questionsPool[questionIndex].right].radio.checked) score++
// if there is remaining question
if (questionIndex + 1 < questionsPool.length) {
// go to the next one and update texts
questionIndex++
updateQuestion()
}
else
// show the final user score
console.log({ score })
}
<div class="choices"></div>
Hope it helped you !

Related

How to remove item form array?

I have the following array in my React naitve app.
const [items, setItems] = useState([
{ answers: [{ id: 1 }, { id: 2 }] },
{ answers: [{ id: 1 }] },
{ answers: [{ id: 1 },] },
]);
I want to delete item from first row with id 2 So the final should look like that
[
{ answers: [{ id: 1 }] },
{ answers: [{ id: 1 }] },
{ answers: [{ id: 1 }] },
]
How can i do that ?
I tried to start like this
const onDelete = useCallback((itemId) => {
var newItems = [...items];
newItems = newItems[0].answers.filter(....) //I don't know how to continue
setItems(newItems);
}, []);
Sorry for the question but I'm new to react-native and javascript!
Assuming that you want to change the first object and you want do dynamically filter the answers based on your itemId, the onDelete function would look like this:
const onDelete = useCallback((itemId) => {
setItems((prev) => [
{ answers: prev[0].answers.filter(({ id }) => id !== itemId) },
...prev.slice(1),
]);
}, []);
I've expanded #sm3sher answer to allow removing answer ids at any index.
const onDelete = useCallback((answerId=2,itemIndex=0)=>{
const newItems = [...items];
let currentItem = newItems[itemIndex]
currentItem.answers = currentItem.answers.filter(({id})=> id !== answerId)
newItems[itemIndex] = currentItem;
setItems(newItems);
},[]);
You should create a new object, whose answers property is the filtered original. The filter callback can be ({id}) => id != 2:
newItems[0] = { answers: newItems[0].answers.filter(({id}) => id != 2) };
newItems = newItems.map(item => { return item.answers.filter(answer => answer.id !== 2)})

'undefined' error prevents last question from displaying...works on previous ones though

I've modified a quiz app from some boilerplate code and I'm getting the dreaded 'undefined' error. I've debugged the error and found that when it gets to the last question in the index, no matter how many questions I create, the last question is displayed but the answer choices are not, although the previous answer choices were displayed.
I looked at several simular questions on SO including Javascript undefined error on last iteration
and I have included return statements in the pertinent functions to no avail.
I just can't wrap my head around why it will print every question and answer set prior the last one just fine, then get to the last question and only display the question with no answers?
Any help would be greatly appreciated. Thanks in advance.
pertinent code:
// script.js
const startButton = document.getElementById('start-btn')
const nextButton = document.getElementById('next-btn')
const questionContainerElement = document.getElementById('question-container')
const questionElement = document.getElementById('question')
const question = questionElement
const answerButtonsElement = document.getElementById('answer-buttons')
const questionImageElement = document.getElementById('question-image')
const hudItemClass = document.getElementsByClassName('hud-item')
const SCORE_POINTS = 4
const MAX_QUESTIONS = 6
const progressBarFull = document.getElementById('progressBarFull')
const progressText = document.getElementById('progressText')
const scoreText = document.getElementById('score')
let shuffledQuestions, currentQuestionIndex = 1, score = 0
startButton.addEventListener('click', startQuiz)
nextButton.addEventListener('click', () => {
currentQuestionIndex++
setNextQuestion()
})
function startQuiz() {
console.log('Started')
startButton.classList.add('hide')
/* Shuffle the questions randomly, subtracting .5 to get a completely random
number. 50% of the time the number will be negative and 50% positive. */
shuffledQuestions = questions.sort(() => Math.random() - .5)
questionContainerElement.classList.remove('hide')
setNextQuestion()
}
function setNextQuestion() {
resetState()
console.log("Inside setNextQuestion prior to call to showQuestion: +" +
"shuffledQuestions[currentQuestionIndex]: ", shuffledQuestions[currentQuestionIndex])
showQuestion(shuffledQuestions[currentQuestionIndex])
console.log("Inside setNextQuestion after call to showQuestion: +" +
"shuffledQuestions[currentQuestionIndex]: ", shuffledQuestions[currentQuestionIndex])
console.log("Inside setNextQuestion: currentQuestionIndex: ", currentQuestionIndex)
return shuffledQuestions[currentQuestionIndex]
}
// Resets everything related to our form when we set a new question.
function resetState() {
// Hide the 'Next' button after selecting an answer and showing the 'Next' button.
nextButton.classList.add('hide')
//hudItemClass.classList.add('hide')
/* If there is a child element inside the answerButtonsElement, remove it. This will
remove the answer buttons from the previous question if any, resetting the
answerButtonsElement.*/
while (answerButtonsElement.firstChild) {
answerButtonsElement.removeChild(answerButtonsElement.firstChild)
}
}
function showQuestion(questions) {
console.log("Inside showQuestion")
progressText.innerText = `Question ${currentQuestionIndex} of ${MAX_QUESTIONS}`
progressBarFull.classList.remove('hide')
progressBarFull.style.width = `${(currentQuestionIndex / MAX_QUESTIONS) * 100}%`
const img = document.createElement('img')
img.src = "../images/code1.png"
// Display the current shuffled question
questionElement.innerText = questions.question //error here on the last question.
// Insert an image at the appropriate question index.
if (questions.id === 2) {
questionImageElement.appendChild(img)
} else {
questionImageElement.innerText = " "
}
// For each answer in the questions array create a button element.
questions.answers.forEach(answer => {
const button = document.createElement('button')
// Place the answer choice text on the button
button.innerText = answer.text
// Styles the button
button.classList.add('btn')
//answer.sort(Math.random() - 0.5)
if (answer.correct) {
button.dataset.correct = answer.correct
}
button.addEventListener('click', selectAnswer)
answerButtonsElement.appendChild(button)
console.log("End showQuestion")
})
return questions.question
}
function selectAnswer(e) {
console.log("Inside selectAnswer")
const selectedButton = e.target
const correct = selectedButton.dataset.correct
if (correct) {
incrementScore(SCORE_POINTS)
}
answerButtonsElement.disabled = true;
/* Should the body class be set for correct or wrong? This will determine which style
to present. */
setStatusClass(document.body, correct)
/*loop through and select the classes for each button.
Comment out code to prevent user from seeing correct answers. */
Array.from(answerButtonsElement.children).forEach(button => {
setStatusClass(button, button.dataset.correct)
})
/* If the number of questions left to answer is greater than the index of the
current question, then diplay the 'Next' button by unhiding it. */
console.log("shuffledQuestions.length inside selectAnswer: ", shuffledQuestions.length)
console.log("currentQuestionIndex inside selectAnswer: ", currentQuestionIndex)
if (shuffledQuestions.length > currentQuestionIndex) {
nextButton.classList.remove('hide')
} else {
//startButton.innerText = 'Restart'
startButton.classList.remove('hide')
}
}
/* This function takes an element and whether or not
it's correct as arguments. If disabled, the user won't be aware of the
correct answer immediately. */
function setStatusClass(element, correct) {
// Clear any status it already has
clearStatusClass(element)
if (correct) {
element.classList.add('correct') // add the 'correct' class with green color.
} else {
element.classList.add('wrong') // add the 'wrong' class with red color.
}
element.removeEventListener('click', selectAnswer)
}
// Clears the class status of the element if it has been set with 'setStatusClass.'
function clearStatusClass(element) {
element.classList.remove('correct')
element.classList.remove('wrong')
}
function incrementScore(num) {
score += num
scoreText.innerText = score
// If the quiz has completed, display the 'end.html page.
if ((shuffledQuestions.length) === 0 || currentQuestionIndex >= MAX_QUESTIONS) {
console.log("shuffledQuestions.length: ", shuffledQuestions.length)
console.log("currentQuestionIndex:", currentQuestionIndex)
console.log("MAX_QUESTIONS: ", MAX_QUESTIONS)
localStorage.setItem('mostRecentScore', score)
return window.location.assign('/end.html')
}
// const questionsIndex = Math.floor(Math.random() * availableQuestions.length)
// Remove or replace existing questions at the current question index.
//availableQuestions.splice(questionsIndex, 1)
}
const questions = [
{
id: 1,
question: ' 1. How many possible values are there for a boolean variable?',
answers: [
{text: '1', correct: false},
{text: '2', correct: true},
{text: '3', correct: false},
{text: 'There is an infinite number of possibilities', correct: false}
]
},
{
id: 2, // image = code1.png
question: '2. What does this Python expression evaluate to?',
answers: [
{text: 'True', correct: false},
{text: 'False', correct: false},
{text: 'type<str>', correct: true},
{text: '<str>type', correct: false}
]
},
{
id: 3,
question: '3. What is the purpose of a function?',
answers: [
{text: 'To provide a way to call code', correct: false},
{text: 'To lessen the impact of variable binding', correct: false},
{text: 'To provide concise code that can be called from anywhere in the program', correct: true},
{text: 'To allow for easy access to variables and parameters', correct: false}
]
},
{
id: 4,
question: '4. Which Python code segment will display \"Hello, world!\" on the screen??',
answers: [
{text: 'display Hello, world!', correct: false},
{text: `print("Hello, world!")`, correct: true},
{text: `print "Hello, world!"`, correct: false},
{text: `"Hello, world!"`, correct: false}
]
},
{
id: 5,
question: ' 5. Which is the most correct answer: What is the difference between an argument and a parameter?',
answers: [
{
text: 'An argument is attached to a function and a parameter is attached to a function ' +
'call', correct: false
},
{
text: 'An argument is attached to a function call and a parameter is associated with a function ' +
'definition', correct: true
},
{text: 'Parameters and arguments are interchangeable terms and can mean the same thing', correct: false},
{text: 'Arguments and parameters are only necessary when functions are long.', correct: false}
]
},
{
id: 6,
question: ' 6. Which is the difference between a while loop and a for loop?',
answers: [
{text: 'A while loop is boolean structure and a for loop is not.', correct: false},
{text: 'A while loop and a for loop are interchangeable.', correct: false},
{text: 'A while loop iterates as long as a certain boolean condition exists.', correct: true},
{text: 'A for loop is used when you don\'t know how many iterations are needed.', correct: false}
]
}
]
Array is 0 indexed, meaning it starts at 0.
questionElement.innerText = questions.question
this above line inside of showQuestion gives you an error because at this point questions is null because of this
currentQuestionIndex = 1
you started your array at 1 and skipped the first question, by the time you get to the last question, showQuestion(shuffledQuestions[currentQuestionIndex]) would be showQuestion(shuffledQuestions[ 6 ]) and you only have 6 questions so at the 6th position is the 7th question(because at position 0 is your first question) which does not exist and returns a null error.
This is all I can gather from your js and in the future you should really post with working code, a simplified example to reproduce the issue so people can work on it
Try this
currentQuestionIndex = 0;
Update other parts of the code where you match ID
I have created an extremely simplified example of your code. only 3 questions and I call setNextQuestion() 3 times which should show each question once. The index is set at 1 and you can see the error that is produced. If you change the index to start at 0, it will work and show all 3 questions
const question = document.getElementById('question')
const SCORE_POINTS = 4
const MAX_QUESTIONS = 3
const answerButtonsElement = document.getElementById('answer-buttons')
const progressText = document.getElementById('progressText')
const scoreText = document.getElementById('score')
let shuffledQuestions, currentQuestionIndex = 1,
score = 0
const questions = [{
id: 1,
question: ' 1. How many possible values are there for a boolean variable?',
answers: [{
text: '1',
correct: false
},
{
text: '2',
correct: true
},
{
text: '3',
correct: false
},
{
text: 'There is an infinite number of possibilities',
correct: false
}
]
},
{
id: 2, // image = code1.png
question: '2. What does this Python expression evaluate to?',
answers: [
{
text: 'True',
correct: false
},
{
text: 'False',
correct: false
},
{
text: 'type<str>',
correct: true
},
{
text: '<str>type',
correct: false
}
]
},
{
id: 3,
question: '3. What is the purpose of a function?',
answers: [{
text: 'To provide a way to call code',
correct: false
},
{
text: 'To lessen the impact of variable binding',
correct: false
},
{
text: 'To provide concise code that can be called from anywhere in the program',
correct: true
},
{
text: 'To allow for easy access to variables and parameters',
correct: false
}
]
}
];
function startQuiz() {
setNextQuestion()
}
function setNextQuestion() {
showQuestion(questions[currentQuestionIndex])
currentQuestionIndex++;
}
// Resets everything related to our form when we set a new question.
function resetState() {}
function showQuestion(questions) {
progressText.innerText = `Question ${currentQuestionIndex} of ${MAX_QUESTIONS}`;
question.innerText = question.innerText + "\n" + questions.question //error here on the last question.
const button = document.createElement('button')
button.innerText = questions.answers[0].text
answerButtonsElement.appendChild(button)
}
setNextQuestion();
setNextQuestion();
setNextQuestion();
<div id="progressText"></div>
<div id="question"></div>
<div id="answer-buttons"></div>
<div id="score"></div>
As others mentioned, your currentQuestionIndex should be 0, along with that change the question ids to start from 0
const startButton = document.getElementById('start-btn')
const nextButton = document.getElementById('next-btn')
const questionContainerElement = document.getElementById('question-container')
const questionElement = document.getElementById('question')
const question = questionElement
const answerButtonsElement = document.getElementById('answer-buttons')
const questionImageElement = document.getElementById('question-image')
const hudItemClass = document.getElementsByClassName('hud-item')
const SCORE_POINTS = 4
const MAX_QUESTIONS = 6
const progressBarFull = document.getElementById('progressBarFull')
const progressText = document.getElementById('progressText')
const scoreText = document.getElementById('score')
let shuffledQuestions, currentQuestionIndex = 0, score = 0;
startButton.addEventListener('click', startQuiz);
nextButton.addEventListener('click', () => {
currentQuestionIndex++
setNextQuestion()
})
function startQuiz() {
console.log('Started')
startButton.classList.add('hide')
/* Shuffle the questions randomly, subtracting .5 to get a completely random
number. 50% of the time the number will be negative and 50% positive. */
shuffledQuestions = questions.sort(() => Math.random() - .5)
questionContainerElement.classList.remove('hide')
setNextQuestion()
}
function setNextQuestion() {
resetState()
console.log("Inside setNextQuestion prior to call to showQuestion: +" +
"shuffledQuestions[currentQuestionIndex]: ", shuffledQuestions[currentQuestionIndex])
showQuestion(shuffledQuestions[currentQuestionIndex])
console.log("Inside setNextQuestion after call to showQuestion: +" +
"shuffledQuestions[currentQuestionIndex]: ", shuffledQuestions[currentQuestionIndex])
console.log("Inside setNextQuestion: currentQuestionIndex: ", currentQuestionIndex)
return shuffledQuestions[currentQuestionIndex]
}
// Resets everything related to our form when we set a new question.
function resetState() {
// Hide the 'Next' button after selecting an answer and showing the 'Next' button.
nextButton.classList.add('hide')
//hudItemClass.classList.add('hide')
/* If there is a child element inside the answerButtonsElement, remove it. This will
remove the answer buttons from the previous question if any, resetting the
answerButtonsElement.*/
while (answerButtonsElement.firstChild) {
answerButtonsElement.removeChild(answerButtonsElement.firstChild)
}
}
function showQuestion(questions) {
console.log("Inside showQuestion")
progressText.innerText = `Question ${currentQuestionIndex+1} of ${MAX_QUESTIONS}`
progressBarFull.classList.remove('hide')
progressBarFull.style.width = `${(currentQuestionIndex / MAX_QUESTIONS) * 100}%`
const img = document.createElement('img')
img.src = "../images/code1.png"
// Display the current shuffled question
questionElement.innerText = questions.question //error here on the last question.
// Insert an image at the appropriate question index.
if (questions.id === 2) {
questionImageElement.appendChild(img)
} else {
questionImageElement.innerText = " "
}
// For each answer in the questions array create a button element.
questions.answers.forEach(answer => {
const button = document.createElement('button')
// Place the answer choice text on the button
button.innerText = answer.text
// Styles the button
button.classList.add('btn')
//answer.sort(Math.random() - 0.5)
if (answer.correct) {
button.dataset.correct = answer.correct
}
button.addEventListener('click', selectAnswer)
answerButtonsElement.appendChild(button)
console.log("End showQuestion")
})
return questions.question
}
function selectAnswer(e) {
console.log("Inside selectAnswer")
const selectedButton = e.target
const correct = selectedButton.dataset.correct
if (correct) {
incrementScore(SCORE_POINTS)
}
answerButtonsElement.disabled = true;
/* Should the body class be set for correct or wrong? This will determine which style
to present. */
setStatusClass(document.body, correct)
/*loop through and select the classes for each button.
Comment out code to prevent user from seeing correct answers. */
Array.from(answerButtonsElement.children).forEach(button => {
setStatusClass(button, button.dataset.correct)
})
/* If the number of questions left to answer is greater than the index of the
current question, then diplay the 'Next' button by unhiding it. */
console.log("shuffledQuestions.length inside selectAnswer: ", shuffledQuestions.length)
console.log("currentQuestionIndex inside selectAnswer: ", currentQuestionIndex)
if (shuffledQuestions.length > currentQuestionIndex) {
nextButton.classList.remove('hide')
} else {
//startButton.innerText = 'Restart'
startButton.classList.remove('hide')
}
}
/* This function takes an element and whether or not
it's correct as arguments. If disabled, the user won't be aware of the
correct answer immediately. */
function setStatusClass(element, correct) {
// Clear any status it already has
clearStatusClass(element)
if (correct) {
element.classList.add('correct') // add the 'correct' class with green color.
} else {
element.classList.add('wrong') // add the 'wrong' class with red color.
}
element.removeEventListener('click', selectAnswer)
}
// Clears the class status of the element if it has been set with 'setStatusClass.'
function clearStatusClass(element) {
element.classList.remove('correct')
element.classList.remove('wrong')
}
function incrementScore(num) {
score += num
scoreText.innerText = score
// If the quiz has completed, display the 'end.html page.
if ((shuffledQuestions.length) === 0 || currentQuestionIndex >= MAX_QUESTIONS) {
console.log("shuffledQuestions.length: ", shuffledQuestions.length)
console.log("currentQuestionIndex:", currentQuestionIndex)
console.log("MAX_QUESTIONS: ", MAX_QUESTIONS)
localStorage.setItem('mostRecentScore', score)
return window.location.assign('/end.html')
}
// const questionsIndex = Math.floor(Math.random() * availableQuestions.length)
// Remove or replace existing questions at the current question index.
//availableQuestions.splice(questionsIndex, 1)
}
const questions = [
{
id: 0,
question: ' 1. How many possible values are there for a boolean variable?',
answers: [
{text: '1', correct: false},
{text: '2', correct: true},
{text: '3', correct: false},
{text: 'There is an infinite number of possibilities', correct: false}
]
},
{
id: 1, // image = code1.png
question: '2. What does this Python expression evaluate to?',
answers: [
{text: 'True', correct: false},
{text: 'False', correct: false},
{text: 'type<str>', correct: true},
{text: '<str>type', correct: false}
]
},
{
id: 2,
question: '3. What is the purpose of a function?',
answers: [
{text: 'To provide a way to call code', correct: false},
{text: 'To lessen the impact of variable binding', correct: false},
{text: 'To provide concise code that can be called from anywhere in the program', correct: true},
{text: 'To allow for easy access to variables and parameters', correct: false}
]
},
{
id: 3,
question: '4. Which Python code segment will display \"Hello, world!\" on the screen??',
answers: [
{text: 'display Hello, world!', correct: false},
{text: `print("Hello, world!")`, correct: true},
{text: `print "Hello, world!"`, correct: false},
{text: `"Hello, world!"`, correct: false}
]
},
{
id: 4,
question: ' 5. Which is the most correct answer: What is the difference between an argument and a parameter?',
answers: [
{
text: 'An argument is attached to a function and a parameter is attached to a function ' +
'call', correct: false
},
{
text: 'An argument is attached to a function call and a parameter is associated with a function ' +
'definition', correct: true
},
{text: 'Parameters and arguments are interchangeable terms and can mean the same thing', correct: false},
{text: 'Arguments and parameters are only necessary when functions are long.', correct: false}
]
},
{
id: 5,
question: ' 6. Which is the difference between a while loop and a for loop?',
answers: [
{text: 'A while loop is boolean structure and a for loop is not.', correct: false},
{text: 'A while loop and a for loop are interchangeable.', correct: false},
{text: 'A while loop iterates as long as a certain boolean condition exists.', correct: true},
{text: 'A for loop is used when you don\'t know how many iterations are needed.', correct: false}
]
}
];

how to create multiple bullets with the forEach function

var data = {
pets:[
{
type: "Dogs Breeds",
name: "Dog",
breed: ["Dalmation", "Poodle", "Shitzu"]
},
{
type: "Cats Breeds",
name:"Cat",
breed:["Ragdoll", "Scottish Fold", "Sphynx"]
},
{
type: "Rabbits Breeds",
name: "Rabbit",
breed: ["Holland Lop", "Rex", "Mini Lop"]
}
]
};
var content = document.getElementById("content")
data.pets.forEach(pets => {
let h1 = document.createElement("h1");
let h1text = document.createTextNode(pets.name);
h1.appendChild(h1text);
content.appendChild(h1);
let h2 = document.createElement("h2");
let h2text = document.createTextNode(pets.type);
h2.appendChild(h2text);
content.appendChild(h2);
let ul = document.createElement("ul")
let li = document.createElement("li");
let text = document.createTextNode(pets.breed);
li.appendChild(text);
ul.appendChild(li);
content.appendChild(ul);
})
This is my code and I need to results to come up as separate bullet points for the breed category. I'm pretty sure the the issue stems from the fact that the ul is in the forEach so each iteration only sees the breed line as one name. I'm not sure how to fix this please help!!
Is this the result you are looking for?
Nested Loop
You can do a nested looping (a .forEach() in another .forEach()) to loop through pets and loop through the breed in pets
var data = {
pets:[
{
type: "Dogs Breeds",
name: "Dog",
breed: ["Dalmation", "Poodle", "Shitzu"]
},
{
type: "Cats Breeds",
name:"Cat",
breed:["Ragdoll", "Scottish Fold", "Sphynx"]
},
{
type: "Rabbits Breeds",
name: "Rabbit",
breed: ["Holland Lop", "Rex", "Mini Lop"]
}
]
};
var content = document.getElementById("content")
data.pets.forEach(pets => {
let h1 = document.createElement("h1");
let h1text = document.createTextNode(pets.name);
h1.appendChild(h1text);
content.appendChild(h1);
let h2 = document.createElement("h2");
let h2text = document.createTextNode(pets.type);
h2.appendChild(h2text);
content.appendChild(h2);
let ul = document.createElement("ul")
pets.breed.forEach(val=>{
let li = document.createElement("li");
let text = document.createTextNode(val);
li.appendChild(text);
ul.appendChild(li);
})
content.appendChild(ul);
})
<div id="content"></div>

How to merge string array values to a particular property in object array in Type Script / Java Script

I have a question object
let question = {
id: 1,
description: 'how is the service',
answers: [
{
id: 1,
description: 'poor'
},
{
id: 2,
description: 'good'
}
]
};
let newquestion = {
description: 'new question',
answers: [
'new poor',
'new good'
]
}
I need to map the answer values to the corresponding description property in the answers array inside the question object.
I need the output to look like,
q = {
id: 1,
description: 'new question',
answers: [
{
id: 1,
description: 'new poor'
},
{
id: 2,
description: 'new good'
}
]
};
i tried,
const q = {...question, ...newquestion};
But I get output like,
q = {
id: 1,
description: 'new question',
answers: [
'new poor',
'new good'
]
};
I'm new to typescript and javascript. Please assist on where I'm going wrong.
If you're okay with mutating the original question, then just loop through the newquestion.asnwers and update the question.answers using their respective index
let question = {id:1,description:'how is the service',answers:[{id:1,description:'poor'},{id:2,description:'good'}]},
newquestion={description:'new question',answers:['new poor','new good']};
newquestion.answers.forEach((description, i) => {
question.answers[i].description = description
})
console.log(question)
If you want to create a new q object, then use map to get the new answers array and create a new object using the spread syntax:
let question = {id:1,description:'how is the service',answers:[{id:1,description:'poor'},{id:2,description:'good'}]},
newquestion={description:'new question',answers:['new poor','new good']};
const newAnswers = newquestion.answers.map((description, i) => (
{ ...question.answers[i], description }
))
const q = { ...question, answers: newAnswers }
console.log(q)
You first need to change answers array in newquestion in desired format.
let question = {id: 1,description: 'how is the service',answers: [{id: 1,description: 'poor'},{id: 2,description: 'good'}]};
let newquestion = {description: 'new question',answers: ['new poor','new good']}
newquestion.answers = newquestion.answers.map((val, index) => ({ id:index+1, description: val }))
let op = {...question, ...newquestion}
console.log(op)
Use a simple map to change the values:
const q = {...question, ...newQuestion};
q.answers = q.answers.map((e, i) => { return { id: i + 1, description: e } });

How can I calculate the shortest and longest paths of this Q&A flow?

I have a Q&A flow like the following:
The basic idea is that depending on the answer chosen for a question, a different question will be asked next.
I am currently representing this Q&A flow with the following JavaScript object:
var QAndAObj = {
1: {
question: 'Question 1',
answers: [
{
answerText: 'Answer 1-1',
nextQuestion: 2
},
{
answerText: 'Answer 1-2',
nextQuestion: 3
}
]
},
2: {
question: 'Question 2',
answers: [
{
answerText: 'Answer 2-1',
nextQuestion: 3
},
{
answerText: 'Answer 2-2',
nextQuestion: null
}
]
},
3: {
question: 'Question 3',
answers: [
{
answerText: 'Answer 3-1',
nextQuestion: 4
},
{
answerText: 'Answer 3-2',
nextQuestion: null
},
{
answerText: 'Answer 3-3',
nextQuestion: null
}
]
},
4: {
question: 'Question 4',
answers: [
{
answerText: 'Answer 4-1',
nextQuestion: null
},
{
answerText: 'Answer 4-2',
nextQuestion: null
}
]
}
};
To show the user a progress bar, I'd like to be able to calculate the longest and shortest paths through the question flow.
My initial thought was to write a recursive function like the following to go down each possible path in the flow:
function recurse(node) {
for (var i = 0; i < node.answers.length; i++) {
if (node.answers[i].nextQuestion) {
recurse(QAndAObj[node.answers[i].nextQuestion]);
}
}
}
The above function does allow me to hit each node in the flow, but I'm not sure how to calculate the longest and shortest paths through the flow.
Any help/advice/code would be greatly appreciated.
Thank you very much.
Take a look at this jsFiddle for a working example.
function shortAndLong(QATree, startNode) {
var paths = [];
function findAllPaths(startNode, currentCost) {
for (var i = 0; i < startNode.answers.length; i++) {
var child = startNode.answers[i];
if (child.nextQuestion == null) {
paths.push(currentCost);
}else {
findAllPaths(QATree[child.nextQuestion], currentCost+1);
}
}
}
findAllPaths(startNode, 1);
return [Math.min.apply(Math, paths), Math.max.apply(Math, paths)]
}
console.debug('ans',shortAndLong(QAndAObj, QAndAObj[1]));//returns [2, 4]
console.debug('ans',shortAndLong(QAndAObj, QAndAObj[2]));//returns [1, 3]
console.debug('ans',shortAndLong(QAndAObj, QAndAObj[3]));//returns [1, 2]
console.debug('ans',shortAndLong(QAndAObj, QAndAObj[4]));//returns [1, 1]
The basics are
Create a list of all paths through the graph, keeping the number of answers needed
Find max and min
var lengthLongestPath = function(input) {
let maxLength = 0;
let pathLength = { 0: 0 }
let lines = input.split("\n");
for (let i = 0; i < lines.length; i++) {
let name = lines[i].replace(/\t/g,"");
let depth = lines[i].length - name.length;
if (name.includes(".")) {
maxLength = Math.max(maxLength, pathLength[depth] + name.length);
} else {
pathLength[depth + 1] = pathLength[depth] + name.length + 1;
}
}
return maxLength;
};
console.log(lengthLongestPath("dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext"))

Categories