Spread object values into input boxes - javascript

I'm trying to write a javascript quiz app. Atm I'm stuck with putting a possible answer into one of the four boxes. So just to make sure you're understanding what I'm trying to become: I fetch questions from an API. The answers are collected in an object and I want to take the answers and put them randomly in my 4 option boxes. I've tried some things but at this moment I have no clue what's going on... Here's my code:
<body>
<div id="questioncontainer" class="main-container">
<div id="progression"><div id="progressfull"></div></div>
<div id="header">
<h2 id="vraagnummer">Vraag #</h2>
<div><h2 id="timer"></h2></div>
</div>
<h2 id="vraaginput">In welke film wordt er kritiek geuit op de socio-economische situatie in Tsjechië in de late jaren 70?</h2>
<div id="antwoordcontainer">
<li id="Qst1"><p class="choice-text" data-number="1">Choice 1</p></li>
<li id="Qst2"><p class="choice-text" data-number="2">Choice 2</p></li>
<li id="Qst3"><p class="choice-text" data-number="3">Choice 3</p></li>
<li id="Qst4"><p class="choice-text" data-number="4">Choice 4</p></li>
<li id="Qst5"><p class="choice-text" data-number="5">Choice 5</p></li>
<li id="Qst6"><p class="choice-text" data-number="6">Choice 6</p></li>
</div>
<button id="Quitgame">Ik stop ermee ze</button>
</div>
</body>
This is less code and has the most important stuff in it.
fetch(myUrl)
.then((res) => {
return res.json();
})
.then((loadedQuestions) => {
for (let i = 0; i < MAX_VRAGEN; i++) {
vragen = loadedQuestions;
vragenTeller++;
mijnVraag.innerHTML = vragen[i].question;
console.log(vragen[i]);
choices.forEach((choice) => {
choice.innerHTML = vragen[i].answers.object;
});
};
startGame();
})
.catch(err => {
console.error(err);
});

Here is a working example. I decided it was better to create the options in HTML, rather than hard code seven answers and hide the ones that doesn't contain a selectable answer. This made the code slightly longer, but more dynamic.
The problem is that the answers came in form of an object, so I needed to use Object.keys(question.answers) so I had a max value to randomize. Then I just randomized a position, and cut that position out while adding answers in a while loop.
I hope the code is self-explanatory. I tried to refactor the code as much as I could.
Oh, and I just preload one question at the time, instead of fetching fifteen like in your original code.
const quizURL = 'https://quizapi.io/api/v1/questions?apiKey=kAFKilHLeEcfLkGE2H0Ia9uTIp1rYHDTIYIHs9qf&limit=1';
var progression = 0;
var questionObj = {};
const questionEl = document.getElementById('vraaginput');
const answerContainerEl = document.getElementById('antwoordcontainer');
const currentQuestionEl = document.getElementById('vraagnummer');
document.getElementById('startGame').addEventListener('click', startGame);
document.getElementById('nextQuestion').addEventListener('click', nextQuestion);
function fetchQuestion() {
fetch(quizURL)
.then((res) => {
return res.json();
})
.then((loadedQuestions) => {
questionObj = loadedQuestions.pop();
})
.catch(err => {
console.error(err);
});
}
function startGame() {
document.getElementById('startGame').setAttribute('hidden', true);
document.getElementById('questionContainer').removeAttribute('hidden');
nextQuestion();
}
function nextQuestion() {
displayQuestion(questionObj);
fetchQuestion();
}
function displayQuestion(question) {
progression++;
currentQuestionEl.innerHTML = `Vraag #${progression}`;
questionEl.innerText = question.question;
randomizeAnswerOptions(question.answers, question.correct_answers);
}
// Here is the randomization for the options.
// I created the radio buttons in javascript.
function randomizeAnswerOptions(options, answers) {
const divContainer = document.createElement('div');
var randomIndex, answerText = '', answerIndex = 0, isExistingAnswer = false, isCorrectAnswer = false;
var optionsKeys = Object.keys(options);
while(optionsKeys.length) {
randomIndex = randomize(optionsKeys.length);
randomIndex = optionsKeys.splice(randomIndex, 1)[0];
answerText = options[randomIndex];
isExistingAnswer = answerText != null;
if (isExistingAnswer) {
isCorrectAnswer = answers[randomIndex + '_correct']
answerIndex++;
divContainer.appendChild(createAnswerRow(answerText, isCorrectAnswer, 'answerInput' + answerIndex));
}
}
answerContainerEl.innerHTML = '';
answerContainerEl.appendChild(divContainer);
}
function createAnswerRow(answerText, isCorrectAnswer, inputId) {
let answerRow = document.createElement('div');
let bullet = document.createElement('input');
let label = document.createElement('label');
bullet.setAttribute('type', 'radio');
bullet.setAttribute('name', 'answer');
bullet.setAttribute('id', inputId);
bullet.setAttribute('data-answer', isCorrectAnswer);
label.setAttribute('for', inputId);
label.innerText = answerText;
answerRow.appendChild(bullet);
answerRow.appendChild(label);
return answerRow;
}
function randomize(max, min) {
return Math.floor(Math.random() * max + (min || 0));
}
fetchQuestion();
#antwoordcontainer > div > div {
margin: 0.25rem;
}
label, input[type="radio"] {
cursor: pointer;
}
label {
padding: 0.25rem;
}
input[type="radio"]:checked ~ label {
background: pink;
}
input[type="radio"][data-answer="true"]:checked ~ label {
background: lightgreen;
}
<button id="startGame">Start Game</button>
<div id="questionContainer" class="main-container" hidden>
<div id="progression">
<div id="progressfull"></div>
</div>
<div id="header">
<h2 id="vraagnummer">Vraag #</h2>
<div>
<h2 id="timer"></h2>
</div>
</div>
<h2 id="vraaginput"></h2>
<div id="antwoordcontainer"><!--ANSWERS--></div>
<button id="nextQuestion">Next Question</button>
<!--<button id="Quitgame">Ik stop ermee ze</button>-->
</div>

Related

How can i use corretly Latex notation via forEach function in vanilla JS?

This question was migrated from Webmasters Stack Exchange because it can be answered on Stack Overflow.
Migrated last month.
I have array examples where i have example (ax^2 + 5x +1 = 0), example (ax^2 + 9x +9 = 0) etc.
I have following logic
const container = document.querySelector("#examples-container");
examples.forEach((ex, i) => {
const example = `
<div class="card">
<div class="example">
${ex.question}
</div>
<button type="button" class="toggle" onclick="toggle(${i})">
Toggle
</button>
<div id="result_${i}" style="display:none" class="result">${ex.answer}</div>
</div>`;
container.innerHTML += example;
});
Somehow is not working i get only string with array value and nothing else. <p>(ax^2 + 5x +1 = 0)</p> Works well
Instead of updating container.innerHTML with each example, compose first the html of all examples, and add that to the container:
const examples = [
{ question: '(ax^2 + 5x +1 = 0)', answer: '(answer for ax^2 + 5x +1 = 0)'},
{ question: '(ax^2 + 9x +9 = 0)', answer: '(answer for ax^2 + 9x +9 = 0)'},
];
function toggle(i) {
const div = document.querySelector(`#result_${i}`);
if (div.style.display !== 'none') {
div.style.display = 'none';
} else {
div.style.display = 'block';
}
}
let html = '';
examples.forEach((ex, i) => {
const example = `
<div class="card">
<div class="example">
${ex.question}
</div>
<button type="button" class="toggle" onclick="toggle(${i})">
Toggle
</button>
<div id="result_${i}" style="display:none" class="result">${ex.answer}</div>
</div>`;
html += example;
});
const container = document.querySelector("#examples-container");
//console.log(html);
container.innerHTML = html;
.card {
border: solid gray 1px;
margin: 5px 0;
padding: 3px 10px;
}
<div id="examples-container"></div>

Trigger function to roll a dice

I have a function to get a random value (1->6) to roll a dice:
const rollDice = () => {
document.dispatchEvent(
new CustomEvent('rollDice', {
detail: { value: Math.floor(Math.random() * 6) + 1 },
bubbles: true,
cancelable: false
})
);
};
Get the value from rollDice() and put in the correct positions, but I don't know why it work incorrectly. The result need show as the picture:
Result
I am newbie here, Can anyone help point out where I'm going wrong?
const rollDice = () => {
document.dispatchEvent(
new CustomEvent('rollDice', {
detail: {
value: Math.floor(Math.random() * 6) + 1
},
bubbles: true,
cancelable: false
})
);
};
let btn = document.querySelector("#roll-button");
btn.addEventListener('click', function() {
var varones = toNumber(parseInt(document.querySelector("#ones p").textContent));
var vartwos = toNumber(parseInt(document.querySelector("#twos p").textContent));
var varthrees = toNumber(parseInt(document.querySelector("#threes p").textContent));
var varfours = toNumber(parseInt(document.querySelector("#fours p").textContent));
var varfives = toNumber(parseInt(document.querySelector("#fives p").textContent));
var varsixes = toNumber(parseInt(document.querySelector("#sixes p").textContent));
rollDice();
document.addEventListener('rollDice', (e) => {
alert(e.detail.value);
if (e.detail.value == 1) {
varones = varones + 1;
}
if (e.detail.value == 2) {
vartwos = vartwos + 1;
}
if (e.detail.value == 3) {
varthrees = varthrees + 1;
}
if (e.detail.value == 4) {
varfours = varfours + 1;
}
if (e.detail.value == 5) {
varfives = varfives + 1;
}
if (e.detail.value == 6) {
varsixes = varsixes + 1;
}
total = varones + vartwos + varthrees + varfours + varfives + varsixes;
document.querySelector("#ones p").textContent = varones;
document.querySelector("#twos p").textContent = vartwos;
document.querySelector("#threes p").textContent = varthrees;
document.querySelector("#fours p").textContent = varfours;
document.querySelector("#fives p").textContent = varfives;
document.querySelector("#sixes p").textContent = varsixes;
document.querySelector("#totals p span").textContent = total;
});
});
function toNumber(a) {
if (isNaN(a)) {
a = 0;
}
return a;
}
<h1>Events Triggered and Emitted</h1>
<h2>Dice Rolls</h2>
<div id="rolls">
<div id="ones">
<span class="dice">⚀</span>
<p>-</p>
</div>
<div id="twos">
<span class="dice">⚁</span>
<p>-</p>
</div>
<div id="threes">
<span class="dice">⚂</span>
<p>-</p>
</div>
<div id="fours">
<span class="dice">⚃</span>
<p>-</p>
</div>
<div id="fives">
<span class="dice">⚄</span>
<p>-</p>
</div>
<div id="sixes">
<span class="dice">⚅</span>
<p>-</p>
</div>
<div id="dice">
<button id="roll-button"><span class="dice">⚂</span></button>
</div>
<div id="totals">
<p>Total rolls: <span>0</span></p>
</div>
</div>
<!-- Template for dice roll 1 -->
<template id="template1"><span class="dice">⚀</span></template>
<!-- Template for dice roll 2 -->
<template id="template2"><span class="dice">⚁</span></template>
<!-- Template for dice roll 3 -->
<template id="template3"><span class="dice">⚂</span></template>
<!-- Template for dice roll 4 -->
<template id="template4"><span class="dice">⚃</span></template>
<!-- Template for dice roll 5 -->
<template id="template5"><span class="dice">⚄</span></template>
<!-- Template for dice roll 6 -->
<template id="template6"><span class="dice">⚅</span></template>
I don't understand all your code, but I think you should write your rollDice event listener out of you click button event listener, because in your example, the event is triggered before the document is listening to this event.
btn.addEventListener('click', () => {
// do something
rollDice()
})
document.addEventListener('rollDice', () => {
// do something
})
First of all, don't type more code than necessary inside an eventListener. If you had refactored your code into a method, you would see that you tried to create an event listener inside an event listener. Here is how an eventListener should be set up:
btn.addEventListener('click', rollDice);
I don't understand why you created an event listener inside rollDice(). Was that part of an assignment? I just called the correct method straight away.
The second part I did was to try to reduce code by looking at similarities in the code. I can use the :nth-child selector to get the proper dice container by using the randomized roll.
rollsDiv.querySelector(`div:nth-child(${roll}) > p`)
The third thing to remember, is to write as short methods as possible, by having them do at most one thing. If you can't do that, try to write methods as a table of content. A person should be able to read the code and understand what's happening just by how it's written. That means refactor complex code, like getCorrectDiceElement(), or using variables and naming them to make each row comprehensible.
These are more tips for intermediate coding, but it could be nice to know this on beforehand. Otherwise, you won't understand your own code when looking at it after a half year. :)
As a present, I added a four more lines (a, b) for functionality that I guess you would like to implement in the future. Good luck!
const rollsDiv = document.getElementById("rolls");
// const totalsDiv = document.getElementById("totals"); // a
const btn = document.getElementById("roll-button");
// var numberOfRolls = 0; // a
const randomize = (max = 6, min = 1) => {
return Math.floor(Math.random() * max) + min;
};
const rollDice = () => {
var roll = randomize();
let diceElement = getCorrectDiceElement(roll);
let previousNumber = toNumber(diceElement.textContent);
// let diceSymbol = document.getElementById("template" + roll).textContent; // b
// console.log(roll, diceElement.parentNode.id)
previousNumber++;
// numberOfRolls++; // a
diceElement.textContent = previousNumber;
}
const getCorrectDiceElement= (roll) => {
return rollsDiv.querySelector(`div:nth-child(${roll}) > p`)
}
function toNumber(a) {
return isNaN(a) ? 0 : a;
}
btn.addEventListener('click', rollDice);
#rolls {
display: flex;
margin-bottom: 1rem;
}
#rolls > div,
#roll-button
{
text-align: center;
font-size: 2rem;
padding: 0rem 1rem;
}
#rolls p {
margin: 0;
}
<h2>Dice Rolls</h2>
<div id="rolls">
<div id="ones">
<span class="dice">⚀</span>
<p>-</p>
</div>
<div id="twos">
<span class="dice">⚁</span>
<p>-</p>
</div>
<div id="threes">
<span class="dice">⚂</span>
<p>-</p>
</div>
<div id="fours">
<span class="dice">⚃</span>
<p>-</p>
</div>
<div id="fives">
<span class="dice">⚄</span>
<p>-</p>
</div>
<div id="sixes">
<span class="dice">⚅</span>
<p>-</p>
</div>
</div>
<div>
<div id="dice">
<button id="roll-button">Roll</button>
</div>
<div id="totals">
<p>Total rolls: <span>0</span></p>
</div>
</div>
<!-- Template for dice roll 1 -->
<template id="template1"><span class="dice">⚀</span></template>
<!-- Template for dice roll 2 -->
<template id="template2"><span class="dice">⚁</span></template>
<!-- Template for dice roll 3 -->
<template id="template3"><span class="dice">⚂</span></template>
<!-- Template for dice roll 4 -->
<template id="template4"><span class="dice">⚃</span></template>
<!-- Template for dice roll 5 -->
<template id="template5"><span class="dice">⚄</span></template>
<!-- Template for dice roll 6 -->
<template id="template6"><span class="dice">⚅</span></template>
[EDIT] Added back the original rollDice() method.
const rollsDiv = document.getElementById("rolls");
// const totalsDiv = document.getElementById("totals"); // a
const btn = document.getElementById("roll-button");
// var numberOfRolls = 0; // a
const randomize = (max = 6, min = 1) => {
return Math.floor(Math.random() * max) + min;
};
const rollDice = () => { // NEW
let eventName = "rollDice";
let eventDetail = {'value': randomize()};
let eventProperties = {detail: eventDetail, 'bubbles': true, 'cancelable': false};
let customEvent = new CustomEvent(eventName, eventProperties);
document.dispatchEvent(customEvent);
};
const handleDiceResult = (event) => {
var eventDetail = event.detail; // NEW
var roll = eventDetail.value;
let diceElement = getCorrectDiceElement(roll);
let previousNumber = toNumber(diceElement.textContent);
// let diceSymbol = document.getElementById("template" + roll).textContent; // b
// console.log(roll, diceElement.parentNode.id)
previousNumber++;
// numberOfRolls++; // a
diceElement.textContent = previousNumber;
}
const getCorrectDiceElement= (roll) => {
return rollsDiv.querySelector(`div:nth-child(${roll}) > p`);
}
function toNumber(a) {
return isNaN(a) ? 0 : a;
}
btn.addEventListener('click', rollDice);
document.addEventListener('rollDice', handleDiceResult); // NEW
#rolls {
display: flex;
margin-bottom: 1rem;
}
#rolls > div,
#roll-button
{
text-align: center;
font-size: 2rem;
padding: 0rem 1rem;
}
#rolls p {
margin: 0;
}
<h2>Dice Rolls</h2>
<div id="rolls">
<div id="ones">
<span class="dice">⚀</span>
<p>-</p>
</div>
<div id="twos">
<span class="dice">⚁</span>
<p>-</p>
</div>
<div id="threes">
<span class="dice">⚂</span>
<p>-</p>
</div>
<div id="fours">
<span class="dice">⚃</span>
<p>-</p>
</div>
<div id="fives">
<span class="dice">⚄</span>
<p>-</p>
</div>
<div id="sixes">
<span class="dice">⚅</span>
<p>-</p>
</div>
</div>
<div>
<div id="dice">
<button id="roll-button">Roll</button>
</div>
<div id="totals">
<p>Total rolls: <span>0</span></p>
</div>
</div>
<!-- Template for dice roll 1 -->
<template id="template1"><span class="dice">⚀</span></template>
<!-- Template for dice roll 2 -->
<template id="template2"><span class="dice">⚁</span></template>
<!-- Template for dice roll 3 -->
<template id="template3"><span class="dice">⚂</span></template>
<!-- Template for dice roll 4 -->
<template id="template4"><span class="dice">⚃</span></template>
<!-- Template for dice roll 5 -->
<template id="template5"><span class="dice">⚄</span></template>
<!-- Template for dice roll 6 -->
<template id="template6"><span class="dice">⚅</span></template>

Draw in two tables vanilla JS

I am working with program that will randomly choose who is making a Christmas gift to whom.
I've created an empty array. When you add a "player" it's pushing the name into two different arrays. Players[] and Players2[].
When you start a draw. The program writes the names of the Players[] on the left hand side and on the right side it writes the drawn names from Players2[].
Every Player from Players2[], after being drawn, is being deleted from the array so in the end we have an empty Players2[] array and full Players[] array.
The problem is: I can't make a working if statement that is checking if the person will not draw himself...
let Players = [];
let Players2 = [];
const addBTN = document.getElementById('addBTN');
const onlyLetters = /^[a-zżźćóęśńłA-ZŻŹĆÓŁĘŚŃŁ ]+$/;
const refreshBTN = document.getElementById('refreshBTN');
const warningBTNyes = document.getElementById('warning-button-yes');
const warningBTNno = document.getElementById('warning-button-no');
const playersList = document.getElementById('playersList');
const playersList2 = document.getElementById('playersList2');
const startBTN = document.getElementById('startBTN');
const drawLotsBTN = document.getElementById('drawLotsBTN');
addBTN.addEventListener('click', function() {
const input = document.getElementById('addPLAYER');
const person = document.getElementById('addPLAYER').value;
if (input.value == "") {
console.log('error_empty_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Wpisz imię osoby!";
} else if (input.value.match(onlyLetters)) {
console.log('good');
Players.push(person);
Players2.push(person);
playersList.innerHTML = playersList.innerHTML + "<br>" + person;
document.getElementById('addPLAYER').value = "";
document.getElementById('errorMSG').style.color = "green";
document.getElementById('errorMSG').innerHTML = "Powodzenie! Dodaj kolejną osobę.";
} else {
console.log('error_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Coś jest nie tak z imieniem. Pamiętaj aby wprowadzać same litery!";
}
});
refreshBTN.addEventListener('click', function() {
document.getElementById('warning').style.display = "block";
});
warningBTNyes.addEventListener('click', function() {
location.reload(true);
document.getElementById('addPLAYER').value = "";
});
warningBTNno.addEventListener('click', function() {
document.getElementById('warning').style.display = "none";
});
startBTN.addEventListener('click', function() {
drawLotsBTN.disabled = false;
const input = document.getElementById('addPLAYER');
const person = document.getElementById('addPLAYER').value;
if (input.value == "") {
} else if (input.value.match(onlyLetters)) {
console.log('good');
Players.push(person);
Players2.push(person);
playersList.innerHTML = playersList.innerHTML + "<br>" + person;
document.getElementById('addPLAYER').value = "";
document.getElementById('errorMSG').style.color = "green";
document.getElementById('errorMSG').innerHTML = "Powodzenie! Zaczynasz losowanie!";
} else {
console.log('error_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Coś jest nie tak z imieniem. Pamiętaj aby wprowadzać same litery!";
}
document.getElementById('addPLAYER').disabled = true;
});
drawLotsBTN.addEventListener('click', function() {
for (let i = 0; i = Players2.length; i++) {
if (Players2.length > 0) {
randomPerson = Math.floor(Math.random() * Players2.length);
if (randomPerson != Players.indexOf(i)) {
console.log(Players2[randomPerson]);
playersList2.innerHTML = playersList2.innerHTML + "<br>" + Players2[randomPerson];
Players2.splice(randomPerson, 1);
}
} else {
console.log('error_empty_array');
}
}
});
<div id="warning" class="warning">
<div class="warning-flex">
<h1>Wszelkie wpisane imiona zostaną usunięte</h1>
<div class="warning-buttons">
<button id="warning-button-yes" class="warning-button-yes">Tak</button>
<button id="warning-button-no" class="warning-button no">Nie</button>
</div>
</div>
</div>
<div class="lotteryContainer">
<div class="left">
<p>dodaj osobę</p>
<div class="addPerson">
<input required id="addPLAYER" type="text">
<button id="addBTN">+</button>
<p id="errorMSG"></p>
<div class="refresh">
<button id="refreshBTN">Od nowa</button>
<button id="startBTN">Start</button>
</div>
</div>
</div>
<div class="right">
<p>Uczestnicy</p>
<div class="tables">
<div class="tableLeft">
<p id=playersList></p>
</div>
<div class="tableRight">
<p id="playersList2"></p>
</div>
</div>
<button id="drawLotsBTN">Losuj</button>
</div>
</div>
<script src="app.js"></script>
Now if I understand what your program aims to do, there is a simple algorithm for it.
How I understand your goal:
You have a list of persons who are going to give presents to each other. (like in secret Santa). It is random who will give to who, but each person gives and receives one gift.
How to implement it (i'd normaly use maps, but I am guessing you are more comfortable with arrays):
players = ["Adam", "Bret", "Clay", "Donald"];
players.sort(function(a, b){return 0.5 - Math.random()}); // shuffles array
gives_to = [...players]; // copy values of array
gives_to.push(gives_to.shift()); // let the first element be the last
Here the first player (players[0]) will give to gives_to[0] and the second to gives_to[1] etc.
I've created this JS script trying to use Trygve Ruud algorithm but it doesn't work like desired.
drawLotsBTN.addEventListener('click', function(){
if(Players.length > 0) {
console.log(Players)
Players.sort(function(a, b){
return 0.5 - Math.random();
});
for(let i = 0; i < Players.length; i++){
playersList2.innerHTML = playersList2.innerHTML + "<br>" + Players[i];
}
}
else{
console.log('error_empty_array');
}
});

Javascript: Don't sum elements that are not visible

I'm trying to sum a list of values from HTML elements, but I want to EXCLUDE values are that hidden using pure JS.
HTML:
<div class="grams">1</div>
<div style="display: none;">
<div class="grams">2</div>
</div>
<div class="milligrams">100</div>
<div class="milligrams">2</div>
<br>
<div>Total:</div>
<div class="servings"></div>
JS:
window.addEventListener('load', function() {
let gramdivs = document.getElementsByClassName("grams");
let milligramdivs = document.getElementsByClassName("milligrams");
var total = 0;
for (let item of gramdivs) {
let itemPrice=parseFloat(item.textContent);
total += itemPrice;
}
for (let item of milligramdivs) {
let itemPrice=parseFloat(item.textContent);
total = total + itemPrice / 1000;
}
document.getElementsByClassName("servings")[0].innerText = total.toFixed(3);
})
https://jsfiddle.net/smhok7yd/2/
In the JS Fiddle, you can see that all the numbers are being added, including the hidden one.
The correct output should be 1.102.
Please note that I cannot change the hierarchy of the HTML.
I am relatively new to JS and have been trying to find a solution all day.
When iterating over elements, check to see if their offsetParent is null - if so, they're not visible:
const getClassValues = (className, multiplier = 1) => [...document.getElementsByClassName(className)]
.filter(elm => elm.offsetParent !== null)
.reduce((a, b) => a + (b.textContent * multiplier), 0);
document.querySelector('.servings').textContent = (
getClassValues('grams') + getClassValues('milligrams', 0.001)
);
<div class="grams">1</div>
<div style="display: none;">
<div class="grams">2</div>
</div>
<div class="milligrams">100</div>
<div class="milligrams">2</div>
<br>
<div>Total:</div>
<div class="servings"></div>
If you set display: none; on the specific grams div you can check for the property before adding it to the total:
https://jsfiddle.net/et6wzph2/28/
function isVisible(e) {
return !!( e.offsetWidth || e.offsetHeight || e.getClientRects().length );
}
window.addEventListener('load', function() {
let gramdivs = document.getElementsByClassName("grams");
let milligramdivs = document.getElementsByClassName("milligrams");
let total = 0;
for (let item of gramdivs) {
if(!isVisible(item)) continue;
let itemPrice = parseFloat(item.textContent);
total += itemPrice;
}
for (let item of milligramdivs) {
if(!isVisible(item)) continue;
let itemPrice = parseFloat(item.textContent);
total = total + itemPrice / 1000;
}
document.getElementsByClassName("servings")[0].innerText = total.toFixed(3);
})
<div class="grams">1</div>
<div style="display: none;">
<div class="grams">2</div>
</div>
<div class="milligrams">100</div>
<div class="milligrams">2</div>
<br>
<div>Total:</div>
<div class="servings"></div>

Difficulty with error "Uncaught TypeError: Cannot read property 'name' of undefined"

I've been working on a JavaScript code in order to make a checkout cart of a pizza, but have been having an issue with the showCart function.
let pizzas=[
{ name:"Pepperoni", img:"pizza.png", price:8.99},
{ name:"Alfredo", img:"pizza.png", price:9.99},
{ name:"Cheese", img:"cheese.png", price:7.99}
];
function registerButtonEvents()
{
let buttons=document.getElementsByTagName("button");
for(let i = 0; i < buttons.length-1; i++)
{
buttons[i].addEventListener("click", function() {
addToCart(i);
});
}
let number = localStorage.getItem("number");
if(number == null)
number = 0;
document.getElementById("num").innerHTML = number;
}
function addToCart(pId)
{
let cartJ = localStorage.getItem("cart");
let cart;
if(cartJ===null) //Cart is empty
{
cart=[];
}
else
{
cart=cartJ.split(",");
}
cart.push(pId);
let number= localStorage.getItem("number");
if(number===null)
number = 0;
document.getElementById("num").innerHTML = `${++number}`;
localStorage.setItem("cart", cart.toString());
localStorage.setItem("number", number);
}
function clearCart()
{
localStorage.removeItem("cart");
localStorage.removeItem("num");
}
function showCart()
{
let cartJ = localStorage.getItem("cart");
let cart = [];
let info = "";
if(cartJ === null)
{
document.getElementById("myCart").innerHTML=`<h2>No items in cart!</h2>`;
}
else
{
cart = cartJ.split(",");
for (let i in cart)
{
let item = pizzas[cart[i]];
info+=
`<div class="row">
<div class="col-md-2 text-center">
<h3>${item.name}</h3>
</div>
<div class="col-md-2 text-center">
<img class="pizza" src="./images/${item.img}" alt="pepperoni">
</div>
<div class="col-md-2 text-center">
<h3>${item.price}</h3>
</div>
<div class="col-md-2 text-center">
<button type="button" class="btn btn-primary" onclick="removePizza(${i})">Remove</button>
</div>
</div>
`;
}
document.getElementById("myCart").innerHTML=info;
}
}
function removePizza(piz)
{
var cart = localStorage.getItem("cart");
cart = cart.split(",");
cart.splice(piz, 1);
if (cart.length == 0)
clearCart();
else
{
localStorage.setItem("cart", cart);
localStorage.setItem("number",cart.length);
}
showCart();
}
Developer tools tell me that the error is in the line in:
let item = pizzas[cart[i]];
but I don't necessarily understand why. If anyone could send some feedback it would be greatly appreciated.
The problem is when you access <h3>${item.name}</h3>. Your item is undefined there because your cart (cart = cartJ.split(",");) probably stores some strings like "Pepperoni" (as you split them using a comma) and after that you want to access the pizzas array using one of those strings instead of an index.

Categories