Javascript: Dynamically inserting svgs from an array - javascript

Building a quiz, and running into an svg snag. I have a folder full of svgs that I would like to appear in each of the multiple choice options (each svg is specific to each answer). Right now, they're looped through, but I can't get a pathway correct in order for them to appear as the ACTUAL svgs instead of just their name (Q1_A, Q1_B and so on). Thus far I've tried using template literals ( icon.innerHTML = /icons/${questions[choicesCounter].icons['choice' + number]}) as well as just using the pathway (tested with, and w/o "") in the array (choice1:/icons/Q1_A.svg). They all come back as undefined or with some other sort of error. Suggestions?
//Questions Array
let questions =[
{
question:"Do you mind crowds?",
icons:{
choice1: "Q1_A.svg",
choice2: "Q1_B.svg",
choice3: "Q1_C.svg",
choice4: "Q1_D.svg",
},
choices:{
choice1: "Crowds don't bother me",
choice2:"I prefer to get off the beaten path",
choice3:"I don't care either way",
choice4:"Crowds mean there is something worth looking at",
}
},
{
question:"Where would you like to stay on your trip?",
icons:{
choice1:"Q2_A.svg",
choice2:"Q2_B.svg",
choice3:"Q2_C.svg",
choice4:"Q2_D.svg",
},
choices:{
choice1:"Hotel",
choice2:"Tent",
choice3:"RV",
choice4:"Cabin"
}
},
{
question:"What activities do you enjoy?",
icons:{
choice1:"Q3_A.svg",
choice2:"Q3_B.svg",
choice3:"Q3_C.svg",
choice4:"Q3_D.svg",
},
choices:{
choice1: "Animal Watching",
choice2:"Hiking",
choice3:"Kayaking",
choice4:"Biking"
}
}];
//Convert to an array, so you can use array functions on it
const icon= Array.from(document.getElementsByClassName('choice_icon'));
const choice= Array.from(document.getElementsByClassName('choice_text'));
let choicesCounter=0;
//Loop through the arry
iconsLoop = () => {
icon.forEach(icon => {
const number = icon.dataset['number'];
icon.innerHTML =questions[choicesCounter].icons['choice' + number];
});
};
iconsLoop();
.multiple-choice-container{
display: flex;
flex-wrap: wrap;
justify-content:center;
}
.choice_container{
height: 8rem;
width: 7rem;
display: flex;
flex-direction: column;
justify-content:center;
align-items: center;
font-size: 1rem;
text-align: center;
margin: 1rem;
border: solid #DDDDDD .2px;
}
.choice_container:hover{
background:#30638E;
color: #fdfdfd;
border:none;
cursor: pointer;
transform: translateY(-0.2rem);
transition: transform 150ms;
box-shadow: 0px 7px 4px 0px rgba(50, 50, 50, 0.75);
}
.choice_container:hover > .choice_prefix{
cursor: pointer;
background: #003D5B;
}
.choice_container:hover > .choice_text{
color: #fdfdfd;
}
.choice_icon{
display:flex;
justify-content: center;
align-items: center;
height:4rem;
width: 3rem;
background:#30638E;
color:#fdfdfd;
margin-bottom: .5rem;
}
.choice_text{
margin-left:.5rem;
width:100%;
border-left: 0;
font-size: 1rem;
}
<div class="choice_container">
<p class="choice_icon" data-number = '1'>A</p>
<p class="choice_text" data-number = '1'> Choice 1</p>
</div>
<div class="choice_container ">
<p class="choice_icon" data-number = '2'>B</p>
<p class="choice_text" data-number = '2'> Choice 2</p>
</div>
<div class="choice_container" >
<p class="choice_icon" data-number = '3'>C</p>
<p class="choice_text" data-number = '3'> Choice 3</p>
</div>
<div class="choice_container" >
<p class="choice_icon" data-number = '4'>D</p>
<p class="choice_text" data-number = '4'> Choice 4</p>
</div>
</div>

Using template literals works, but you need to embed the svg in an img tag if you're setting the innerHTML property.
A little hard to demo, but the below should illustrate the point
//Questions Array
let questions = [{
question: "Do you mind crowds?",
icons: {
choice1: "Q1_A here",
choice2: "Q1_B here",
choice3: "Q1_C here",
choice4: "Q1_D here",
},
choices: {
choice1: "Crowds don't bother me",
choice2: "I prefer to get off the beaten path",
choice3: "I don't care either way",
choice4: "Crowds mean there is something worth looking at",
}
}]
//Convert to an array, so you can use array functions on it
const icon = Array.from(document.getElementsByClassName('choice_icon'));
const choice = Array.from(document.getElementsByClassName('choice_text'));
let choicesCounter = 0;
//Loop through the arry
iconsLoop = () => {
icon.forEach(icon => {
const number = icon.dataset['number'];
icon.innerHTML = `<img src="http://placeholder.pics/svg/100x100/888888/EEE/${questions[choicesCounter].icons['choice' + number]}">`;
});
};
iconsLoop();
.multiple-choice-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.choice_container {
height: 8rem;
width: 7rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 1rem;
text-align: center;
margin: 1rem;
border: solid #DDDDDD .2px;
}
.choice_container:hover {
background: #30638E;
color: #fdfdfd;
border: none;
cursor: pointer;
transform: translateY(-0.2rem);
transition: transform 150ms;
box-shadow: 0px 7px 4px 0px rgba(50, 50, 50, 0.75);
}
.choice_container:hover>.choice_prefix {
cursor: pointer;
background: #003D5B;
}
.choice_container:hover>.choice_text {
color: #fdfdfd;
}
.choice_icon {
display: flex;
justify-content: center;
align-items: center;
height: 4rem;
width: 3rem;
background: #30638E;
color: #fdfdfd;
margin-bottom: .5rem;
}
.choice_text {
margin-left: .5rem;
width: 100%;
border-left: 0;
font-size: 1rem;
}
<div class="choice_container">
<p class="choice_icon" data-number='1'>A</p>
<p class="choice_text" data-number='1'> Choice 1</p>
</div>
<div class="choice_container ">
<p class="choice_icon" data-number='2'>B</p>
<p class="choice_text" data-number='2'> Choice 2</p>
</div>
<div class="choice_container">
<p class="choice_icon" data-number='3'>C</p>
<p class="choice_text" data-number='3'> Choice 3</p>
</div>
<div class="choice_container">
<p class="choice_icon" data-number='4'>D</p>
<p class="choice_text" data-number='4'> Choice 4</p>
</div>
</div>

Related

on click div get big and back to normal

I created a mini Qcm, when I click on an answer the check moves on the div on which I clicked
const reps = document.getElementsByClassName('rep');
[].forEach.call(reps, function(rep) {
$(rep).click(function() {
if (!rep.querySelector('.check')) {
[].forEach.call(reps, function(repToDel) {
if (repToDel.querySelector('.check')) {
repToDel.querySelector('.check').remove()
}
})
$(rep).last().append('<div class="check"><object data="check.svg" width="20" > </object></div>')
}
})
})
.container {
padding: 5%;
display: grid;
gap: 20px;
grid-template-columns: 1fr;
}
.question_title {
font-size: 18px;
font-weight: 500;
text-align: center;
}
.container_reps {
display: grid;
justify-items: center;
gap: 10px;
}
.rep {
display: flex;
align-items: center;
border: 1px solid black;
padding: 0 10px;
max-width: 15%;
min-width: 170px;
border-radius: 10px;
cursor: pointer;
overflow: hidden;
}
.dot_rep {
background-color: black;
color: white;
margin-right: 7px;
padding: 5px 10px;
border-radius: 5px;
}
.text_rep {
font-weight: 700;
}
.check {
margin-left: 20%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js" integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div class="container">
<div class="question_title">
<p>Je suis une Question, quelle est votre reponse ?</p>
</div>
<div class="container_reps">
<div class="rep">
<span class="dot_rep">A</span>
<p class="text_rep">Reponse 1</p>
</div>
<div class="rep">
<span class="dot_rep">B</span>
<p class="text_rep">Reponse 2</p>
</div>
<div class="rep">
<span class="dot_rep">C</span>
<p class="text_rep">Reponse 3</p>
</div>
<div class="rep">
<span class="dot_rep">D</span>
<p class="text_rep">Reponse 4</p>
</div>
</div>
</div>
but when I click the div get big and back to normal at the same time,I tried the overflow:hidden, but it didn't work.
the change between the check must be done smoothly.
With this JQuery code and if the image is present it's works
$(function(){
const reps = document.getElementsByClassName('rep');
[].forEach.call(reps,function(rep){
$(rep).click(function(){
// Remove Check Div only for Old Check
[].forEach.call(reps,function(repToDel) { if(repToDel.querySelector('.check')) repToDel.querySelector('.check').remove(); });
// Put Check Div for New Check
if(! rep.querySelector('.check')) $(rep).last().append('<div class="check"><object data="check.png" width="20" > </object></div>');
});
});
});

Change a button onclick href based on multiple IDs

I have an order summary. The order summary is a collection of 5 different HTML IDs based on user selection. I'm trying to get the "checkout button" to link to different URLs based on different configurations corresponding to different HTML IDs.
For example, if the user selects "BRAZIL", "2 BAGS", "WHOLE BEAN", "EVERY 4 WEEKS", "ALL ROAST TYPES" the checkout button would take them to a specific URL and so on specific for that selection. If they make a different selection, they should be taken to a different URL.
I'm assuming a for loop and if... else statement would do the trick but I can't seem to figure it out. I feel like I'm close but maybe I'm way off.
What I currently have:
// CHECKOUT BUTTON CONDITIONALS
function checkoutButton() {
let checkoutBtnClick = document.querySelectorAll("#change-coffee, #change-bag, #change-grind-type, #change-delivery, #change-roast-type").innerHTML;
if (checkoutBtnClick === "BRAZIL", "2 BAGS", "WHOLE BEAN", "EVERY 4 WEEKS", "ALL ROAST TYPES") {
document.getElementById("box-summary-checkout-button").setAttribute('onclick', 'window.location.href="https://www.google.com/"');
} else if (checkoutBtnClick === "BRAZIL", "2 BAGS", "GROUND", "EVERY 4 WEEKS", "ALL ROAST TYPES") {
document.getElementById("box-summary-checkout-button").setAttribute('onclick', 'window.location.href="https://www.facebook.com/"');
}
}
/* ORDER SUMMARY */
.container-summary {
display: flex;
border: 3px solid none;
justify-content: center;
margin-bottom: 50px;
font-family: 'lato', sans-serif;
}
.box-summary {
height: 20.5rem;
width: 30rem;
background: #eee;
border-radius: 6px;
}
.box-summary-title {
display: flex;
justify-content: center;
font-size: 20px;
font-weight: 600;
letter-spacing: .03rem;
margin-top: 25px;
color: #433d3d;
line-height: .95em;
}
.box-summary-block {
display: flex;
justify-content: space-around;
margin: 1rem 3rem;
font-size: 13px;
font-weight: 600;
letter-spacing: .03rem;
line-height: 1.9em;
color: #393939;
}
.box-summary-block-coffee {
display: flex;
justify-content: center;
margin: 1rem 4rem;
font-size: 13px;
font-weight: 600;
letter-spacing: .03rem;
line-height: 1.9em;
color: #393939;
}
.box-summary-option-coffee {
margin-left: .75rem;
}
.box-summary-block-right {
text-align: end;
}
.box-summary-category2-left,
.box-summary-category2-right {
margin-top: .6em;
}
.box-summary-option-bags,
.box-summary-option-grind,
.box-summary-option-delivery,
.box-summary-option-roast,
.box-summary-option-coffee {
color: #3e718a;
}
.box-summary-shipment-plus-price {
display: flex;
justify-content: space-evenly;
margin-left: 60px;
margin-right: 60px;
margin-bottom: 10px;
margin-top: 20px;
font-size: 15px;
font-weight: 600;
letter-spacing: .03rem;
line-height: .95em;
color: #433d3d;
}
.box-summary-order-button-container {
display: flex;
justify-content: center;
}
.box-summary-order-button {
padding: 15px 30px 15px 30px;
font-size: 15px
}
<!--ORDER SUMMARY CONTAINER-->
<div class="container-summary">
<div class="box-summary">
<div class="box-summary-title">
ORDER SUMMARY
</div>
<div class="box-summary-block-coffee">
COFFEE SELECTION: <span class="box-summary-option-coffee" id="change-coffee">BRAZIL</span>
</div>
<div class="box-summary-block">
<div class="box-summary-block-left">
<div class="box-summary-category1-left">
# OF BAGS
</div>
<div class="box-summary-option-bags" id="change-bag">
2 BAGS
</div>
<div class="box-summary-category2-left">
GRIND TYPE
</div>
<div class="box-summary-option-grind" id="change-grind-type">
WHOLE BEAN
</div>
</div>
<div class="box-summary-block-right">
<div class="box-summary-category1-right">
DELIVERY
</div>
<div class="box-summary-option-delivery" id="change-delivery">
EVERY 4 WEEKS
</div>
<div class="box-summary-category2-right">
ROAST TYPE
</div>
<div class="box-summary-option-roast" id="change-roast-type">
ALL ROAST TYPES
</div>
</div>
</div>
<div class="box-summary-order-summary">
<div class="box-summary-shipment-plus-price">
<span class="box-summary-price-per-shipment">
PRICE PER SHIPMENT:
</span>
<span class="box-summary-order-price" id="box-summary-total-price">
$90
</span>
</div>
<div class="box-summary-order-button-container">
<button class="box-summary-order-button" id="box-summary-checkout-button" onclick="checkoutButton()">
CONTINUE TO CHECKOUT
</button>
I think what you're looking for, is something like this :
// List Shopify codes for all possible variations as a hierarchical object
let variations = {
// coffee
"BRAZIL" : {
// bag
"2 BAGS" : {
// delivery
"EVERY 4 WEEKS" : {
// roast type
"ALL ROAST TYPES" : {
// grind type
"WHOLE BEAN" :"42755456106732:1",
"GROUND" :"42755456106500:1",
...
},
...
},
...
},
...
},
...
};
// CHECKOUT BUTTON CONDITIONALS
function checkoutButton() {
// Select each node you want to process
let coffee = document.getElementById("change-coffee").innerHTML.trim().toUpperCase();
let bag = document.getElementById("change-bag").innerHTML.trim().toUpperCase();
let delivery = document.getElementById("change-delivery").innerHTML.trim().toUpperCase();
let roastType = document.getElementById("change-roast-type").innerHTML.trim().toUpperCase();
let grindType = document.getElementById("change-grind-type").innerHTML.trim().toUpperCase();
try {
// Go find the Shopify code
// If only grindType is not known, this returns 'undefined'
// If any of the other values are not known, this triggers an error
// The order of the variables should match the order in your hierarchical object
let shopifyCode = variations[coffee][bag][delivery][roastType][grindType];
if(typeof shopifyCode === 'undefined') {
// Now you also throw an error if just grindType is not known
throw "shopifyCode can't be undefined";
}
// Build your URL
const URL = `https://www.server.com/thepartthatstaysthesame/${shopifyCode}`;
// Display URL in console (useful for testing purposes)
console.log(URL);
// Visit the URL you just created
window.location.href = URL;
} catch (error) {
// Do your error handling here
console.error('Variation unknown');
}
}
You can use a map.
Also recommended to use addEventListener
Note the spread operator [...] to make an array of the node list to map
I also assume the IDs we are looking for all start with change
// CHECKOUT BUTTON CONDITIONALS
document.getElementById("box-summary-checkout-button").addEventListener("click", () => {
const parms = [...document.querySelectorAll("[id^=change]")]
.map(div => `${div.id}=${div.textContent.trim().replace(/ /g,"+")}`);
const url = `https://www.server.com/someprocesses?${parms.join("&")}`;
console.log(url);
//window.location.href = url;
})
/* ORDER SUMMARY */
.container-summary {
display: flex;
border: 3px solid none;
justify-content: center;
margin-bottom: 50px;
font-family: 'lato', sans-serif;
}
.box-summary {
height: 20.5rem;
width: 30rem;
background: #eee;
border-radius: 6px;
}
.box-summary-title {
display: flex;
justify-content: center;
font-size: 20px;
font-weight: 600;
letter-spacing: .03rem;
margin-top: 25px;
color: #433d3d;
line-height: .95em;
}
.box-summary-block {
display: flex;
justify-content: space-around;
margin: 1rem 3rem;
font-size: 13px;
font-weight: 600;
letter-spacing: .03rem;
line-height: 1.9em;
color: #393939;
}
.box-summary-block-coffee {
display: flex;
justify-content: center;
margin: 1rem 4rem;
font-size: 13px;
font-weight: 600;
letter-spacing: .03rem;
line-height: 1.9em;
color: #393939;
}
.box-summary-option-coffee {
margin-left: .75rem;
}
.box-summary-block-right {
text-align: end;
}
.box-summary-category2-left,
.box-summary-category2-right {
margin-top: .6em;
}
.box-summary-option-bags,
.box-summary-option-grind,
.box-summary-option-delivery,
.box-summary-option-roast,
.box-summary-option-coffee {
color: #3e718a;
}
.box-summary-shipment-plus-price {
display: flex;
justify-content: space-evenly;
margin-left: 60px;
margin-right: 60px;
margin-bottom: 10px;
margin-top: 20px;
font-size: 15px;
font-weight: 600;
letter-spacing: .03rem;
line-height: .95em;
color: #433d3d;
}
.box-summary-order-button-container {
display: flex;
justify-content: center;
}
.box-summary-order-button {
padding: 15px 30px 15px 30px;
font-size: 15px
}
<!--ORDER SUMMARY CONTAINER-->
<div class="container-summary">
<div class="box-summary">
<div class="box-summary-title">
ORDER SUMMARY
</div>
<div class="box-summary-block-coffee">
COFFEE SELECTION: <span class="box-summary-option-coffee" id="change-coffee">BRAZIL</span>
</div>
<div class="box-summary-block">
<div class="box-summary-block-left">
<div class="box-summary-category1-left">
# OF BAGS
</div>
<div class="box-summary-option-bags" id="change-bag">
2 BAGS
</div>
<div class="box-summary-category2-left">
GRIND TYPE
</div>
<div class="box-summary-option-grind" id="change-grind-type">
WHOLE BEAN
</div>
</div>
<div class="box-summary-block-right">
<div class="box-summary-category1-right">
DELIVERY
</div>
<div class="box-summary-option-delivery" id="change-delivery">
EVERY 4 WEEKS
</div>
<div class="box-summary-category2-right">
ROAST TYPE
</div>
<div class="box-summary-option-roast" id="change-roast-type">
ALL ROAST TYPES
</div>
</div>
</div>
<div class="box-summary-order-summary">
<div class="box-summary-shipment-plus-price">
<span class="box-summary-price-per-shipment">
PRICE PER SHIPMENT:
</span>
<span class="box-summary-order-price" id="box-summary-total-price">
$90
</span>
</div>
<div class="box-summary-order-button-container">
<button class="box-summary-order-button" id="box-summary-checkout-button">
CONTINUE TO CHECKOUT
</button>

How to remove the class when the element is clicked again JS

I have accordion block.
When you click on an inactive item, it becomes active.
The active class is removed from the previous item.
It all works.
But now I needed to make it so that when you click on the active item again, it becomes inactive again.
I also have a function so that hiding / opening items happens without jerks.
But it doesn't work with the current JS code:
function setHeight() {
if (content.offsetHeight) {
content.style.height = 0;
} else {
content.style.height = accordText.offsetHeight + 'px';
};
};
How can I do that?
const accordItems = document.querySelectorAll('.accordion__item');
accordItems.forEach(item => {
const accordText = item.querySelector('.accordion__text');
const content = item.querySelector('.accordion__content');
item.addEventListener('click', (event) => {
accordItems.forEach(item => {
item.classList.remove('active');
});
item.classList.add('active');
});
});
#import url("https://fonts.googleapis.com/css2?family=Lora&display=swap");
#import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap");
body {
margin: 0;
padding: 0;
box-sizing: border-box;
color: #1f1f1f;
background: #f2f2f2; }
html {
font-size: 62.5%; }
h5 {
margin: 0; }
p {
margin: 0; }
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: auto;
max-width: 140rem; }
.section-accordion {
display: flex;
align-items: center;
max-width: 134rem;
margin: auto; }
.accordion-image {
width: 630px;
height: 450px;
background: url("https://eternel.maitreart.com/wp-content/uploads/2021/07/creat-home-1.jpg");
background-repeat: no-repeat;
background-size: cover; }
.accordion {
width: 63rem;
height: auto;
margin-left: 8rem; }
.accordion__item {
border-top: 1px solid #a8a6a4;
overflow: hidden;
transition: height .5s;
padding-bottom: 1rem; }
.accordion__item.active {
height: 100%; }
.accordion__item:last-child {
border-bottom: 1px solid #a8a6a4; }
.accordion__header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 2rem 1rem 1rem 1rem;
cursor: pointer; }
.accordion__title {
font-family: 'Lora';
font-size: 2.4rem;
line-height: 1.2;
font-weight: 400;
text-transform: uppercase; }
.accordion__icon {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 2rem;
height: 2rem;
transition: transform .5s ease; }
.accordion__icon span:first-child {
transform: rotate(90deg) translateX(1px);
width: 1.4rem;
height: .1rem;
background: currentColor; }
.accordion__icon span {
display: block;
width: 1.4rem;
height: .1rem;
background: currentColor;
cursor: pointer; }
.accordion__content {
font-family: 'Roboto', sans-serif;
font-size: 1.6rem;
line-height: 1.62;
font-weight: 400;
padding: 0 1rem 0 1rem;
height: 0;
overflow: hidden;
transition: height .5s; }
.accordion__item.active > .accordion__header .accordion__icon {
transform: rotate(45deg); }
.accordion__item.active > .accordion__content {
margin-bottom: 1.2rem;
height: 100%; }
<div class="container">
<section class="section-accordion">
<div class="accordion-image"></div>
<div class="accordion">
<div class="accordion__item active">
<div class="accordion__header">
<h5 class="accordion__title">Visual direction</h5>
<div class="accordion__icon">
<span></span>
<span></span>
</div>
</div>
<div class="accordion__content">
<p class="accordion__text">Carried nothing on am warrant towards. Polite in of in oh needed itself silent course.
Assistance travelling so especially do prosperous appearance mr no celebrated.
Wanted easily in my called formed suffer. Songs hoped sense.
</p>
</div>
</div>
<div class="accordion__item">
<div class="accordion__header">
<h5 class="accordion__title">Event production</h5>
<div class="accordion__icon">
<span></span>
<span></span>
</div>
</div>
<div class="accordion__content">
<p class="accordion__text">Carried nothing on am warrant towards. Polite in of in oh needed itself silent course.
Assistance travelling so especially do prosperous appearance mr no celebrated.
Wanted easily in my called formed suffer. Songs hoped sense.
</p>
</div>
</div>
<div class="accordion__item">
<div class="accordion__header">
<h5 class="accordion__title">Brand creation</h5>
<div class="accordion__icon">
<span></span>
<span></span>
</div>
</div>
<div class="accordion__content">
<p class="accordion__text">Carried nothing on am warrant towards. Polite in of in oh needed itself silent course.
Assistance travelling so especially do prosperous appearance mr no celebrated.
Wanted easily in my called formed suffer. Songs hoped sense.
</p>
</div>
</div>
<div class="accordion__item">
<div class="accordion__header">
<h5 class="accordion__title">Design concept</h5>
<div class="accordion__icon">
<span></span>
<span></span>
</div>
</div>
<div class="accordion__content">
<p class="accordion__text">Carried nothing on am warrant towards. Polite in of in oh needed itself silent course.
Assistance travelling so especially do prosperous appearance mr no celebrated.
Wanted easily in my called formed suffer. Songs hoped sense.
</p>
</div>
</div>
</div>
</div>
</section>
</div>
Can you do something like this?
accordItems.forEach(item => {
const accordText = item.querySelector('.accordion__text');
const content = item.querySelector('.accordion__content');
item.addEventListener('click', (event) => {
const wasActive = item.classList.contains('active');
accordItems.forEach(item => {
item.classList.remove('active');
});
if (!wasActive) {
item.classList.add('active');
}
});
});
This makes a clicked item active only if it wasn't active when the click occurred. Toggling is another option, if you are okay with more than one item being active at the same time:
accordItems.forEach(item => {
const accordText = item.querySelector('.accordion__text');
const content = item.querySelector('.accordion__content');
item.addEventListener('click', (event) => {
item.classList.toggle('active');
});
});
Instead of adding and removing class you can use a shorthand syntax toggle it makes things easier.
It remove the class if the class is present vice versa
Here's the code for it
item.classList.toggle('active')
const accordItems = document.querySelectorAll('.accordion__item');
accordItems.forEach(item => {
const accordText = item.querySelector('.accordion__text');
const content = item.querySelector('.accordion__content');
item.addEventListener('click', (event) => {
accordItems.forEach(item => {
item.classList.toggle('active');
});
item.classList.add('active');
});
});

How do I get my Code to show only one picture per question

const question = document.querySelector('#question');
const choices = Array.from(document.querySelectorAll('.choice-text'));
const progressText = document.querySelector('#progressText');
const scoreText = document.querySelector('#score');
let currentQuestion = {}
let acceptingAnswers = true
let score = 0
let questionCounter = 0
let availableQuestions = []
let questions = [
{
question: "Question 1",
choice1: "Spain",
choice2: "France",
choice3: "Colombia",
choice4: "China",
answer: 2,
},
{
question:"Question 2",
choice1: "Hungary",
choice2: "Switzerland",
choice3: "Chile",
choice4: "Austrailia",
answer: 1,
},
{
question: "Question 3",
choice1: "Chile",
choice2: "Brazil",
choice3: "New Zealand",
choice4: "Morocco",
answer: 4,
},
]
const SCORE_POINTS = 1
const MAX_QUESTIONS = 6
function startGame(){
questionCounter = 0
score = 0
availableQuestions = [...questions]
getNewQuestion()
}
function getNewQuestion(){
if(availableQuestions.length === 0 || questionCounter > MAX_QUESTIONS) {
localStorage.setItem('mostRecentScore', score)
return window.location.assign('end.html')
}
questionCounter++
progressText.innerText = `Question ${questionCounter} of ${MAX_QUESTIONS}`
// progressBarFull.style.width = `${(questionCounter/MAX_QUESTIONS) * 100}%`
const questionsIndex = Math.floor(Math.random() * availableQuestions.length)
currentQuestion = availableQuestions[questionsIndex]
question.innerText = currentQuestion.question
choices.forEach(choice => {
const number = choice.dataset['number']
choice.innerText = currentQuestion['choice' + number]
})
availableQuestions.splice(questionsIndex, 1)
acceptingAnswers = true
}
choices.forEach(choice => {
choice.addEventListener('click', e => {
if(!acceptingAnswers) return
acceptingAnswers = false
const selectedChoice = e.target
const selectedAnswer = selectedChoice.dataset['number']
let classToApply = selectedAnswer == currentQuestion.answer ? 'correct' : 'incorrect'
if(classToApply === 'correct') {
incrementScore(SCORE_POINTS)
}
selectedChoice.parentElement.classList.add(classToApply)
setTimeout(() => {
selectedChoice.parentElement.classList.remove(classToApply)
getNewQuestion()
}, 1000)
})
})
function incrementScore(num){
score +=num
scoreText.innerText = score
}
startGame()
body{
background-color: gray;
}
*{
box-sizing: border-box;
margin: 0;
padding: 0;
font-size: 62.5%;
}
h1{
text-align: center;
font-size: 5.4rem;
color: black;
margin-bottom: 5rem;
}
h2{
font-size: 4.2rem;
margin-bottom: 4rem;
}
.container{
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
max-width: 80rem;
margin: 0 auto;
padding: 2rem;
}
.flex-column{
display: flex;
flex-direction: column;
}
.flex-center{
justify-content: center;
align-items: center;
}
.justify-center{
justify-content: center;
}
.text-center{
text-align: center;
}
.hidden{
display: none;
}
.btn{
font-size: 2.4rem;
padding:2rem 0;
width: 30rem;
text-align: center;
margin-bottom: 1rem;
text-decoration: none;
color: rgb(29, 26, 26);
background: lightblue;
border-radius: 4px;
}
.btn:hover{
cursor: pointer;
background: teal;
box-shadow: rgb(130, 170, 183);
transition:transform 150ms;
transform: scale(1.03);
}
.btn[disabled]:hover{
cursor: not-allowed;
box-shadow: none;
transform: none;
}
body {
color: black;
}
.choice-container {
display: flex;
margin-bottom: 0.8rem;
width: 100%;
border-radius: 4px;
background: lightblue;
font-size: 3rem;
min-width: 80rem;
}
.choice-container:hover {
cursor: pointer;
box-shadow: 0 0.4rem 1.4rem 0 rgba(6, 103, 247, 0.5);
transform: scale(1.02);
transform: transform 100ms;
}
.choice-prefix {
padding: 2rem 2.5rem;
color: black
}
.choice-text {
padding: 2rem;
width: 100%;
}
.progressText{
text-align: center;
}
.correct {
background: green;
}
.incorrect {
background: red;
}
/* Heads up Display */
#hud {
display: flex;
justify-content: space-between;
}
.hud-prefix {
text-align: center;
font-size: 2rem;
}
.hud-main-text {
text-align: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Quiz Page</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="game.css">
<style>
img{
align-self: center;
width: 80px;
height: 150;
padding-bottom: 50px;
}
</style>
</head>
<body>
<div class="container">
<div id="game" class="justify-center flex-column">
<div id="hud">
<div class="hud-item">
<p id="progressText" class="hud-prefix">
Question
</p>
<div id="progressBarFull"></div>
</div>
<div class="hud-item">
<p class="hud-prefix">
Score
</p>
<h1 class="hud-main-text" id="score">
0
</h1>
</div>
</div>
<h1 id="question">What is the answer to this question</h1>
<img id="france" src="france.jpg">
<img id="hungary" src="hungary.jpg">
<img id="morocco" src="morocco.jpg">
<div class="choice-container">
<p class="choice-prefix">A</p>
<p class="choice-text" data-number="1">Choice</p>
</div>
<div class="choice-container">
<p class="choice-prefix">B</p>
<p class="choice-text" data-number="2">Choice 2</p>
</div>
<div class="choice-container">
<p class="choice-prefix">C</p>
<p class="choice-text" data-number="3">Choice 3</p>
</div>
<div class="choice-container">
<p class="choice-prefix">D</p>
<p class="choice-text" data-number="4">Choice 4</p>
</div>
</div>
</div>
<script src="Flag.js"></script>
</body>
</html>
Im creating a quiz game that shows the user a country flag and the user has to choose from four choices to pick the correct one. Currently I have all the questions flags being shown because I cant figure out how to show just one image per question. Is there a way to hide the other pictures or put the image to specify an image to a question. The quiz also randomizes each time you play so if the first time you play is different the second time.
I added a code snippet of just the flag questions. my entire code as a home page and an end page that shows the final score and lets the user play again.
Here you go: https://codepen.io/chrisbradshaw/pen/yLaLLVo.
Remove the flag images from HTML and add:
<img src="" alt="quiz show question" id="flagImage" />
Include flag image in question objects:
{
question: "Question 1",
choice1: "Spain",
choice2: "France",
choice3: "Colombia",
choice4: "China",
answer: 2,
flagImage: 'https://placekitten.com/200/300'
}
Create a variable for #flagImage DOM img:
const flagImageHtml = document.querySelector('#flagImage');
Update the src of the #flagImage DOM img when you change the current question:
flagImageHtml.src = currentQuestion.flagImage;

How can I create a list where I can add and remove inputs via buttons?

I've an idea. For this I need a list like this draw:
So the main idea is to have a plus and a minus button. When a users presses the plus button, another input get's added. When pressing the minus button beside each input, the related input should be removed.
So I've startet with this here but I'm not very with it and the functionality is not given yet. How can I deal with this a smart way? Is there a problem with the id's? I mean I could copy a row or insert it (with JS) but how can I get the values later of all inputs in one map (with JS) for example? A lot of questions..
.out-task {
display: flex;
margin-bottom: 8px;
}
.delete-task-button {
margin-left: 6px;
background: red;
}
.button {
width: 30px;
height: 30px;
display: block;
border-radius: 50%;
color: white;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.add-task-button {
background: green;
}
<div class="wrapper">
<label>Tasks</label>
<div id="tasks-wrapper">
<div class="out-task">
<input type="text" id="task" name="task" value="">
<span class="delete-task-button button">-</span>
</div>
</div>
<span class="add-task-button button">+</span>
</div>
Thanks for helping me out!!!
As I have criticized everyone, I let you do the same on my code:
const ListTasks = document.querySelector('#wrapper > div')
, PosInsertTask = document.querySelector('#wrapper > div > span.add-task-button')
, taskWrapper = document.querySelector('#template > div')
;
ListTasks.onclick=e=>
{
if (e.target.classList.contains('add-task-button'))
{
let newTask = taskWrapper.cloneNode(true)
ListTasks.insertBefore(newTask, PosInsertTask)
}
else if (e.target.classList.contains('delete-task-button'))
{
ListTasks.removeChild(e.target.closest('.out-task'))
}
}
.out-task {
display : flex;
margin-bottom: 8px;
}
.delete-task-button {
margin-left: 6px;
background : red;
}
.button {
width : 30px;
height : 30px;
display : block;
border-radius : 50%;
color : white;
display : flex;
justify-content: center;
align-items : center;
cursor : pointer;
font-weight : bold;
}
#wrapper { display: inline-block; border: 1px solid grey; padding:.8em;}
#wrapper h4 { text-align: center; }
.add-task-button {
background: green;
margin: auto;
}
#template { display: none;}
<div id="wrapper">
<h4>Tasks</h4>
<div>
<div class="out-task">
<input type="text" value="">
<span class="delete-task-button button">-</span>
</div>
<span class="add-task-button button">+</span>
</div>
</div>
<div id="template">
<div class="out-task">
<input type="text" value="">
<span class="delete-task-button button">-</span>
</div>
</div>

Categories

Resources