Parent height relative to child height with hidden: overflow - javascript

So, my parent container is quiz-container, the child of that is #quiz, the child of that is. slide. The quiz/slide needs to be absolute, or the Q/A will shuffle its way down the page as the next question button is clicked.
The quiz-container should automatically adjust its height based on the size of the #quiz or. slide question/answer so it appears correctly on the phone and so you don't need to scroll forever to click the next button. The button already moves relative to the height of the quiz-container, so that's what I want.
I tried to set a height in px then have it adjust itself with an
overflow: hidden;
but that didn't work.
<style type="text/css">
body {
font-size: 20px;
font-family: 'Work Sans', sans-serif;
color: #333;
font-weight: 300;
text-align: center;
background-color: #f8f6f0;
}
h1 {
font-weight: 300;
margin: 0px;
padding: 10px;
font-size: 20px;
background-color: #444;
color: #fff;
}
.section-description {
margin-bottom: 20px;
}
.question {
position: relative;
font-size: 30px;
margin-bottom: 10px;
}
.answers {
position: relative;
margin-bottom: 20px;
text-align: left;
display: inline-block;
}
.answers label {
display: block;
margin-bottom: 10px;
}
button {
position: absolute;
font-family: 'Work Sans', sans-serif;
font-size: 22px;
background-color: #279;
color: #fff;
border: 0px;
border-radius: 3px;
padding: 20px;
cursor: pointer;
margin-top: 30px;
margin-bottom: 0px;
z-index: 100;
clear: both;
display: block;
bottom: calc(0px + (100% - var(--slide-height)));
left: 60%;
transform: translateX(-10%);
}
button:hover {
background-color: #38a;
}
.slide {
position: absolute;
height: auto;
left: 0px;
top: 0px;
width: 100%;
z-index: 1;
opacity: 0;
transition: opacity 0.5s;
border: 5px purple solid;
}
.active-slide {
opacity: 1;
z-index: 2;
}
.quiz-container {
position: relative;
height: 600px;
overflow: hidden;
display: flex;
border: 5px red solid;
}
.previous {
/* styles for the second button */
position: absolute;
left: 30%; /* aligns element horizontally to center of parent */
transform: translateX(-10%); /* moves element to left by 50% of its own width */
bottom: calc(0px + (100% - var(--slide-height)));
}
#quiz > .slide {
position: absoluate;
height: min-content;
overflow: hidden;
border: 5px solid blue;
}
</style>
<h1>QUIZ</h1>
<div class="quiz-container">
<div id="quiz">
</div>
</div>
<div class="block"><button class="previous" id="previous" type="button">Previous Question</button><button id="next" type="button">Next Question</button><button id="submit" type="button">Submit Quiz</button></div>
<div id="results"> </div>
<div id="results"> </div>
<div id="category-scores"> </div>
<div id="raw-scores"> </div>
<script>
// variable for categories
const resultsContainer = document.getElementById('results');
const categoryScoresContainer = document.getElementById('category-scores');
const rawScoresContainer = document.getElementById('raw-scores');
const quizContainer = document.getElementById("quiz");
const submitButton = document.getElementById("submit");
(function() {
// Functions
function buildQuiz() {
// variable to store the HTML output
const output = [];
// for each question...
myQuestions.forEach((currentQuestion, questionNumber) => {
// variable to store the list of possible answers
const answers = [];
// and for each available answer...
for (letter in currentQuestion.answers) {
// ...add an HTML radio button
answers.push(
`<label id="quiz-container">
<input id="answers" type="radio" name="question${questionNumber}" value="${letter}">
${letter} :
${currentQuestion.answers[letter]}
</label>`
);
}
// add this question and its answers to the output
output.push(
`<div id="quiz-container" class="slide">
${currentQuestion.description ? `<div class="section-description">${currentQuestion.description}</div>` : ''}
<div class="question"> ${currentQuestion.question} </div>
<div class="answers"> ${answers.join("")} </div>
</div>`
);
});
// combine output list into one string of HTML and put it on the page
quizContainer.innerHTML = output.join("");
const nextButton = document.getElementById("next");
nextButton.addEventListener("click", function() {
const description = document.getElementById("description");
if (description) quizContainer.removeChild(description);
});
}
function showResults() {
// gather answer containers from our quiz
const answerContainers = quizContainer.querySelectorAll('.answers');
// keep track of user's answers
let numCorrect = 0;
// for each question...
myQuestions.forEach((currentQuestion, questionNumber) => {
// find selected answer
const answerContainer = answerContainers[questionNumber];
const selector = `input[name=question${questionNumber}]:checked`;
const userAnswer = (answerContainer.querySelector(selector) || {}).value;
// if answer is correct
if (userAnswer === currentQuestion.correctAnswer) {
// add to the number of correct answers
numCorrect++;
scores[currentQuestion.category]++;
//multiplies by 2 for final result
scores[currentQuestion.category]++;
}
});
//hide myQuestions
quizContainer.innerHTML = "";
// show number of correct answers out of total
resultsContainer.innerHTML = `${numCorrect} out of ${myQuestions.length}`;
categoryScoresContainer.innerHTML = `
<p>Word Knowledge = ${scores.wk/2} out of 18</p>
<p>Arithmetic Reasoning = ${scores.ar/2} out of 15</p>
<p>Paragraph Comprehension = ${scores.pc/2} out of 8</p>
<p>Mathmematics Knowledge = ${scores.mk/2} out of 13</p>`;
// hide previous, next and submit button, and make quiz read-only
const previousButton = document.getElementById("previous");
const nextButton = document.getElementById("next");
const submitButton = document.getElementById("submit");
previousButton.style.display = "none";
nextButton.style.display = "none";
submitButton.style.display = "none";
const inputElements = quizContainer.querySelectorAll("input");
inputElements.forEach(input => {
input.setAttribute("disabled", true);
});
//add restart button
const restartButton = document.getElementById("restart");
restartButton.style.display = "block";
restartButton.addEventListener("click", function() {
location.reload();
});
}
function showSlide(n) {
slides[currentSlide].classList.remove('active-slide');
slides[n].classList.add('active-slide');
currentSlide = n;
if (currentSlide === 0) {
previousButton.style.display = 'none';
} else {
previousButton.style.display = 'inline-block';
}
if (currentSlide === slides.length - 1) {
nextButton.style.display = 'none';
submitButton.style.display = 'inline-block';
} else {
nextButton.style.display = 'inline-block';
submitButton.style.display = 'none';
}
}
function showNextSlide() {
showSlide(currentSlide + 1);
}
function showPreviousSlide() {
showSlide(currentSlide - 1);
}
// Variables
const quizContainer = document.getElementById('quiz');
const resultsContainer = document.getElementById('results');
const submitButton = document.getElementById('submit');
const myQuestions = [{
category: "wk",
description: "<h2>PART I - WORD KNOWLEDGE. YOU WILL HAVE 7 MINUTES TO COMPLETE.</h2><br /><h4>THIS TEST HAS QUESTIONS ABOUT THE MEANING OF WORDS. EACH QUESTION HAS AN UNDERLINED WORD. YOU ARE TO DECIDE WHICH OF THE FOUR POSSIBLE ANSWERS MOST NEARLY MEANS THE SAME AS THE UNDERLINED WORD. THEN WRITE THE ANSWER ON THE APPROPRIATE SPACE ON YOUR ANSWER SHEET.</h4>",
question: "1. <b><u>SMALL</u></b> MOST NEARLY MEANS?",
answers: {
a: "STURDY",
b: "ROUND",
c: "CHEAP",
d: "LITTLE"
},
correctAnswer: "d"
},
{
category: "ar",
description: "<h2>PART II - ARITHMETIC REASONING - YOU WILL HAVE FOURTEEN (14) MINUTES:</h2><h4>THIS IS A TEST OF YOUR ABILITY TO SOLVE ARITHMETIC PROBLEMS. USE YOUR SCRATCH PAPER FOR ANY FIGURING YOU NEED TO DO.</h4>",
question: "1. TWO AUTOMOBILES START TOGETHER FROM THE SAME PLACE AND TRAVEL ALONG THE SAME ROUTE. THE FIRST AVERAGES 40 MPH. THE SECOND 55 MPH. HOW MANY MILES FURTHER ALONG THE ROUTE IS THE SECOND AUTO AT THE END OF THE 5TH HOUR?",
answers: {
a: "55 x 5",
b: "55 - 40",
c: "(55x5) - (40x5)",
d: "55/5 - 40/5"
},
correctAnswer: "c"
},
{
category: "pc",
description: "<h2>PART III - PARAGRAPH COMPREHENSION - YOU WILL HAVE SEVEN (7) MINUTES:</h2>",
question: "1. THE DUTY OF THE LIGHTHOUSE KEEPER IS TO KEEP THE LIGHT BURNING NO MATTER WHAT HAPPENS, SO THAT SHIPS WILL BE WARNED OF THE PRESENCE OF DANGEROUS ROCKS. IF A SHIPWRECK SHOULD OCCUR NEAR THE LIGHTHOUSE, EVEN THOUGH HE WOULD LIKE TO AID IN THE RESCUE OF IT'S CREW AND PASSENGERS, THE LIGHTHOUSE KEEPER MUST......",
answers: {
a: "STAY AT HIS LIGHT",
b: "RUSH TO THEIR AID",
c: "TURN OUT THE LIGHT",
d: "QUICKLY SOUND THE SIREN"
},
correctAnswer: "a"
},
{
category: "mk",
description: "<h2>PART IV - MATHEMATICS KNOWLEDGE - YOU WILL HAVE TWELVE (12) MINUTES:</h2>",
question: "1. WHICH OF THE FOLLOWING IS THE SMALLEST PRIME NUMBER GREATER THAN 200?",
answers: {
a: "201",
b: "205",
c: "211",
d: "214"
},
correctAnswer: "c"
},
];
// Kick things off
buildQuiz();
// Pagination
const previousButton = document.getElementById("previous");
const nextButton = document.getElementById("next");
const slides = document.querySelectorAll(".slide");
let currentSlide = 0;
let scores = {
wk: 0,
ar: 0,
pc: 0,
mk: 0,
};
// Show the first slide
showSlide(currentSlide);
// Event listeners
submitButton.addEventListener('click', showResults);
previousButton.addEventListener("click", showPreviousSlide);
nextButton.addEventListener("click", showNextSlide);
})();
</script>

Related

How to add a smooth animation to the progress bar

When I click I want to smoothly add segments to the progress bar. They are added but instantly. What could be the problem?
I tried to implement a smooth animation with setInterval, but nothing comes out. Percentages are also added instantly.
let progressBar = document.querySelector(".progressbar");
let progressBarValue = document.querySelector(".progressbar__value");
const body = document.querySelector("body");
let progressBarStartValue = 0;
let progressBarEndValue = 100;
let speed = 50;
body.addEventListener("click", function(e) {
if (progressBarStartValue === progressBarEndValue) {
alert("you have completed all the tasks");
} else {
let progress = setInterval(() => {
if (progressBarStartValue != 100) {
progressBarStartValue += 10;
clearInterval(progress);
}
progressBarValue.textContent = `${progressBarStartValue}%`;
progressBar.style.background = `conic-gradient(
#FFF ${progressBarStartValue * 3.6}deg,
#262623 ${progressBarStartValue * 3.6}deg
)`;
}, speed);
}
});
.progressbar {
position: relative;
height: 150px;
width: 150px;
background-color: #262623;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.progressbar::before {
content: "";
position: absolute;
height: 80%;
width: 80%;
background-color: #0f0f0f;
border-radius: 50%;
}
.progressbar__value {
color: #fff;
z-index: 9;
font-size: 25px;
font-weight: 600;
}
<main class="main">
<section class="statistic">
<div class="container">
<div class="statistic__inner">
<div class="statistic__text">
<h2 class="statistic__title">You're almost there!</h2>
<p class="statistic__subtitle">keep up the good work</p>
</div>
<div class="progressbar"><span class="progressbar__value">0%</span></div>
</div>
</div>
</section>
</main>
This may not be exactly what you're looking for, but with the conic-gradient() implementation you're using, I'd recommend checking out a library call anime.js.
Here's an example with your implementation (same html and css):
// your.js
let progressBar = document.querySelector(".progressbar");
let progressBarValue = document.querySelector(".progressbar__value");
const body = document.querySelector("body");
// Switched to object for target in anime()
let progressBarObject = {
progressBarStartValue: 0,
progressBarEndValue: 100,
progressBarAnimationValue: 0 * 3.6 // New value needed for smoothing the progress bar, since the progress value needs to be multiplied by 3.6
}
// Not necessary, but I recommend changing the event listener to pointerup for better support
// Also not necessary, I changed function to arrow function for my own preference
body.addEventListener("pointerup", e => {
e.preventDefault()
if (progressBarObject.progressBarStartValue === progressBarObject.progressBarEndValue) {
alert("you have completed all the tasks");
} else {
let newValue = 0 // Needed so we can set the value, before it's applied in anime()
if (progressBarObject.progressBarStartValue != 100) {
// Math.ceil() allows us to round to the nearest 10 to guarantee the correct output
newValue = Math.ceil((progressBarObject.progressBarStartValue + 10) / 10) * 10;
}
// Optional: Prevents accidentally going over 100 somehow
if (newValue > 100) {
newValue = 100
}
anime({
targets: progressBarObject,
progressBarStartValue: newValue,
progressBarAnimationValue: newValue * 3.6,
easing: 'easeInOutExpo',
round: 1, // Rounds to nearest 1 so you don't have 0.3339...% displayed in progressBarValue
update: () => {
progressBar.style.backgroundImage = `conic-gradient(
#FFF ${progressBarObject.progressBarAnimationValue}deg,
#262623 ${progressBarObject.progressBarAnimationValue}deg)`;
progressBarValue.textContent = `${progressBarObject.progressBarStartValue}%`;
},
duration: 500
});
}
});
Here's a CodePen using the anime.js CDN: Circular Progress Bar Smoothing
If you don't want to use a javascript library, then I'd recommend switching from the conic-gradient() to something else. I hear using an .svg circle with stroke and stroke-dasharray can work great with CSS transition.
You shouldn't setInterval your progress variable like this. instead, put it as a global variable outside the function then use it to gradually add 1 as long as the start value is less than progress, and you still can control the speed with your speed variable.
let progressBar = document.querySelector(".progressbar");
let progressBarValue = document.querySelector(".progressbar__value");
const body = document.querySelector("body");
let progressBarStartValue = 0;
let progressBarEndValue = 100;
let speed = 50;
let progress = 0;
body.addEventListener("click", function(e) {
if (progressBarStartValue === progressBarEndValue) {
alert("you have completed all the tasks");
} else {
progress += 10;
setInterval(() => {
if (progressBarStartValue < progress) {
progressBarStartValue += 1;
clearInterval();
}
progressBarValue.textContent = `${progressBarStartValue}%`;
progressBar.style.background = `conic-gradient(
#FFF ${progressBarStartValue * 3.6}deg,
#262623 ${progressBarStartValue * 3.6}deg
)`;
}, speed);
}
});
.progressbar {
position: relative;
height: 150px;
width: 150px;
background-color: #262623;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 3px solid red;
}
.progressbar::before {
content: "";
position: absolute;
height: 80%;
width: 80%;
background-color: #0f0f0f;
border-radius: 50%;
border: 3px solid blue;
}
.progressbar__value {
color: #fff;
z-index: 9;
font-size: 25px;
font-weight: 600;
}
<main class="main">
<section class="statistic">
<div class="container">
<div class="statistic__inner">
<div class="statistic__text">
<h2 class="statistic__title">You're almost there!</h2>
<p class="statistic__subtitle">keep up the good work</p>
</div>
<div class="progressbar"><span class="progressbar__value">0%</span></div>
</div>
</div>
</section>
</main>

How to write a simple marquee effect with javascript

I need everyone's help. I currently need to implement a marquee effect. The yellow box needs to be scrolled up to show the name. Every time I scroll, I have to stay in the middle of the box for 1 second before continuing to scroll. I can find such an example on the Internet. , but the logic of this program is a bit difficult for me to understand for urban beginners. I wonder if anyone would like to provide a simpler and easier-to-understand writing method if I want to achieve this marquee effect?
​​Sorry, I am a beginner in the program, the current logic More complex programs are more difficult to understand.
function slideLine(box, stf, delay, speed, h) {
var slideBox = document.getElementById(box);
var delay = delay || 1000,
speed = speed || 20,
h = h || 40;
var tid = null,
pause = false;
var s = function() {
tid = setInterval(slide, speed);
};
var slide = function() {
if (pause) return;
slideBox.scrollTop += 1;
if (slideBox.scrollTop % h == 0) {
clearInterval(tid);
slideBox.appendChild(slideBox.getElementsByTagName(stf)[0]);
slideBox.scrollTop = 0;
setTimeout(s, delay);
}
};
setTimeout(s, delay);
}
slideLine("kanban_info", "p", 1000, 25, 40);
.kanban {
position: absolute;
margin: 0 auto;
width: 278px;
height: 50px;
background-color: yellow;
left: 50%;
transform: translate(-50%);
text-align: center;
line-height: 6;
}
.kanban .kenban_wrap {
height: 38px;
transform: translateY(28px);
overflow: hidden;
}
.kanban .kenban_wrap .kanban_info {
line-height: 38px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="kanban">
<div class="kenban_wrap" id='kanban_info'>
<p class="kanban_info">Allen</p>
<p class="kanban_info">james</p>
<p class="kanban_info">jack</p>
</div>
</div>
By combining scroll-behavior with anchor tags that are programmatically clicked you can simplify it. This should be easier to understand and you can go from there, even if it might not be the best solution.
let links = document.querySelectorAll("a"); // List of links
let div = document.querySelector("div");
let index = 0;
let t = 2000; // setTimeout duration
// Change Scroll behavior to prevent the animation from the last to first list item
function scrollBeh() {
if(index == 1) {
div.style.scrollBehavior = "auto";
t = 0; // Timeout duration to 0 to prevent `1` being shown longer than other list items
} else {
div.style.scrollBehavior = "smooth";
t = 2000;
}
}
// Loop through list items
function resetInd() {
if(index < 3) {
index++;
} else {
index = 0;
}
}
function clickLinks() {
links[index].click();
resetInd();
scrollBeh();
setTimeout(clickLinks, t);
}
setTimeout(clickLinks, t);
div {
width: 200px;
height: 100px;
background-color: darkblue;
overflow: hidden;
scroll-behavior: smooth;
}
li {
height: 100px;
list-style: none;
}
a {
text-decoration: none;
color: #FFF;
font-size: 50px;
}
<div>
<ul>
<li id="one">1</li>
<li id="two">2</li>
<li id="three">3</li>
<li id="one_loop">1</li>
</ul>
</div>

Adding ratings and Heart icons too each movie name

I have to create a basic Movie listing site wherein i can add or remove a movie from favorites. Instead of the add to favourite button , I want to add the heart icon from bootstrap. Also the rating of the film (star icons) under each film name.
// DUMMY names
var names = {
1: {
name: "Red Notice",
desc: "An Interpol agent tracks the world's most wanted art thief.",
img: "rn.jpg",
},
2: {
name: "Dune",
desc: "the son of a noble family entrusted with the protection of the most valuable asset and most vital element in the galaxy.",
img: "dune.jpg",
},
3: {
name: " Escape Room",
desc: "Six people unwillingly find themselves locked in another series of escape rooms, slowly uncovering what they have in common to survive..",
img: "esc.jpg",
},
4: {
name: "Antim: The Final Truth",
desc: "The cop played by Salman fights the land mafia in the film. ",
img: "4.jpg",
},
5: {
name: "Dhamaka",
desc: "Reassigned from TV to radio, a frustrated anchor sees both danger and opportunity when he receives threatening calls on the air. ",
img: "5.jpg",
}
};
var movie = {
// (A) PROPERTIES
hPdt: null, // HTML names list
hItems: null, // HTML current movie
items: {}, // Current items in movie
// (B) LOCALSTORAGE movie
// (B1) SAVE CURRENT movie INTO LOCALSTORAGE
save: function() {
localStorage.setItem("movie", JSON.stringify(movie.items));
},
// (B2) LOAD movie FROM LOCALSTORAGE
load: function() {
movie.items = localStorage.getItem("movie");
if (movie.items == null) { movie.items = {}; } else { movie.items = JSON.parse(movie.items); }
},
// (B3) EMPTY ENTIRE movie
nuke: function() {
if (confirm("Empty favourite List?")) {
movie.items = {};
localStorage.removeItem("movie");
movie.list();
}
},
// (C) INITIALIZE
init: function() {
// (C1) GET HTML ELEMENTS
movie.hPdt = document.getElementById("movie-names");
movie.hItems = document.getElementById("movie-items");
// (C2) DRAW names LIST
movie.hPdt.innerHTML = "";
let p, item, part;
for (let id in names) {
// WRAPPER
p = names[id];
item = document.createElement("div");
item.className = "p-item";
movie.hPdt.appendChild(item);
// PRODUCT IMAGE
part = document.createElement("img");
part.src = "img/" + p.img;
part.className = "p-img";
item.appendChild(part);
// PRODUCT NAME
part = document.createElement("div");
part.innerHTML = p.name;
part.className = "p-name";
item.appendChild(part);
// PRODUCT DESCRIPTION
part = document.createElement("div");
part.innerHTML = p.desc;
part.className = "p-desc";
item.appendChild(part);
// ADD TO fav
part = document.createElement("input");
part.type = "button";
part.value = "Add to Favorites";
part.className = "movie p-add";
part.onclick = movie.add;
part.dataset.id = id;
item.appendChild(part);
}
// (C3) LOAD movie FROM PREVIOUS SESSION
movie.load();
// (C4) LIST CURRENT movie
movie.list();
},
// (D) LIST CURRENT movie ITEMS (IN HTML)
list: function() {
// (D1) RESET
movie.hItems.innerHTML = "";
let item, part, pdt;
let empty = true;
for (let key in movie.items) {
if (movie.items.hasOwnProperty(key)) { empty = false; break; }
}
// (D2) movie IS EMPTY
if (empty) {
item = document.createElement("div");
item.innerHTML = "List is empty";
movie.hItems.appendChild(item);
} else {
let p, total = 0,
subtotal = 0;
for (let id in movie.items) {
// ITEM
p = names[id];
item = document.createElement("div");
item.className = "c-item";
movie.hItems.appendChild(item);
// NAME
part = document.createElement("div");
part.innerHTML = p.name;
part.className = "c-name";
item.appendChild(part);
// REMOVE
part = document.createElement("input");
part.type = "button";
part.value = "X";
part.dataset.id = id;
part.className = "c-del movie";
part.addEventListener("click", movie.remove);
item.appendChild(part);
}
// EMPTY BUTTONS
item = document.createElement("input");
item.type = "button";
item.value = "Remove all from Favorites";
item.addEventListener("click", movie.nuke);
item.className = "c-empty movie";
movie.hItems.appendChild(item);
}
},
// (E) ADD ITEM INTO movie
add: function() {
if (movie.items[this.dataset.id] == undefined) {
movie.items[this.dataset.id] = 1;
} else {
movie.items[this.dataset.id]++;
}
movie.save();
movie.list();
},
// (G) REMOVE ITEM FROM movie
remove: function() {
delete movie.items[this.dataset.id];
movie.save();
movie.list();
},
};
window.addEventListener("DOMContentLoaded", movie.init);
body {
background-color: rgb(210, 241, 223);
}
.title {
text-align: center;
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
padding-bottom: 20px;
}
#movie-wrap {
font-family: arial, sans-serif;
display: grid;
grid-template-columns: 80% 20%;
margin: 0 auto;
max-width: 4000px;
}
input.movie,
button.movie {
font-weight: bold;
font-size: 1em;
padding: 10px;
border: none;
color: rgb(58, 56, 158);
background: #929cf5;
cursor: pointer;
}
.name {
text-align: center;
}
/* (B) names LIST */
#movie-names {
display: grid;
grid-template-columns: auto auto;
grid-gap: 30px;
padding: 10px;
}
.p-item {
padding: 10px;
border: 1px solid #aaa;
text-align: center;
}
.p-name {
text-transform: uppercase;
font-weight: bold;
font-size: 1.1em;
}
.p-img {
max-width: 180px;
}
.p-desc {
color: #777;
font-size: 0.9em;
line-height: 1.5em;
}
input.p-add {
width: 80%;
}
/* (D) CURRENT SHOPPING movie */
#movie-items {
padding: 10px;
background: #d8cbcb;
margin: 10px;
}
.c-item {
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
}
.c-name {
width: 80%;
font-size: 1.3em;
line-height: 1.5em;
}
.c-del {
width: 20%;
}
input.c-empty {
width: 100%;
margin-top: 10px;
}
/* (E) RESPONSIVE */
#media (max-width: 768px) {
#movie-wrap {
grid-template-columns: 60% 40%;
}
#movie-names {
grid-template-columns: auto;
}
}
<!DOCTYPE html>
<html>
<head>
<title>MOVIE LISTING WEBSITE</title>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<h1 class="title">Movie Listing App</h1>
<div id="movie-wrap">
<div class="name">
<h2>Movie Names</h2>
<div id="movie-names">
</div>
</div>
<div class="name">
<h2>Favorites</h2>
<div id="movie-items">
</div>
</div>
</div>
</body>
</html>
Also I would like to know if there is a less complicated method to do make this site. Any help would be appreciated.
ps: I dont know why the code is showing error here. It runs properly on my pc
see: https://www.tutorialrepublic.com/twitter-bootstrap-tutorial/bootstrap-icons.php
you first need to import bootstrap to your header in your html page:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.5.0/font/bootstrap-icons.css">
and then you can use icons like this:
<span class="bi-star"></span>

Transition not triggering within event handler

Here is an example of what I want to achieve for the problem at hand:
https://codepen.io/binnny/pen/ExPpggQ
When I click the button, no translateY() is being triggered to slide down the #main_card so that #next_card appears. I also want to reset the transition, because each next card eventually becomes the main card, and new content has to be created for the next card.
So for each click it goes:
main: A --> next: B
main: B --> next: C
main: C -- next: D
What is actually happening is that the content is changing, but there is no slide down transitioning. Not sure how to remedy this to get the expected outcome for each click?
HTML
<main id="quote-box">
<div id="next_card">
<p id="_text"></p>
<p id="_author"></p>
</div>
<div id="main_card">
<p id="text"></p>
<p id="author"></p>
</div>
</main>
Sass
#quote-box {
position: relative;
overflow: hidden;
width: 80vw;
height: 300px;
margin: auto;
border: 7px solid;
#next_card {
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
text-align: center;
width: 100%;
height: inherit;
}
#main_card {
#extend #next_card;
position: absolute;
top: 0;
}
}
JavaScript
var quotes = [
{text: "Hello Earth!", author: "Me"}, {text: "Hello Mars!", author: "You"},
{text: "Hello Pluto", author: "Dunno"}, {text: "Hello Jupiter!", author: "Fiddo"},
{text: "Hello Uranus!", author: "Bozo"}, {text: "Hello Venus!", author: "Mom"}
];
var button = document.querySelector("button");
window.onload = function(event) {
var next_card = document.getElementById("next_card");
var main_card = document.getElementById("main_card");
[next_card, main_card].forEach(function(card) {
create_quote(card);
});
};
function create_quote(card) {
// style the card with quote
card.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]
var selected_quote = quotes[Math.floor(Math.random() * quotes.length)];
var card_attrs = Array.prototype.slice.call(card.children);
card_attrs.forEach(function(attr) {
attr.innerText = selected_quote[attr.id.replace("_", "")];
});
return card;
}
function shift_quote(event) {
event.preventDefault();
var next_card = document.getElementById("next_card");
var main_card = document.getElementById("main_card");
main_card.style.transform = "translateY(300px)";
var updated_main_card = next_card.cloneNode(true);
updated_main_card.id = "main_card";
next_card.parentElement.replaceChild(updated_main_card, main_card);
for (var i = 0; i < 2; i++) {
create_quote(next_card);
}
}

Why do I have to click button twice before event fires?

A simple multiple choice quiz with one problem I can't solve. At first When I clicked the 'next question' button the next question and answers didn't show only when clicked a second time the next question and answers showed.
When I placed runningQuestion++ above questions[runningQuestion].displayAnswers()
like I did in the nextQuestion function the initial problem is solved but reappears after the last question when you are asked to try again. Only now when you click 'try again' now ofcourse it skips the first question.
class Question {
constructor(question, answers, correct) {
this.question = question;
this.answers = answers;
this.correct = correct;
}
displayAnswers() {
document.querySelector('.question').innerHTML = `<div class="q1">${this.question}</div>`
let i = 0
let answers = this.answers
for (let el of answers) {
let html = `<div class="name" id=${i}>${el}</div>`
document.querySelector('.answers').insertAdjacentHTML('beforeend', html)
i++
}
}
}
const q1 = new Question('What\'s the capitol of Rwanda?', ['A: Dodoma', 'B: Acra', 'C: Kigali'], 2);
const q2 = new Question('What\'s is the square root of 0?', ["A: Not possible", 'B: 0', 'C: 1'], 1);
const q3 = new Question('Who was Rome\'s first emperor?', ['A: Tiberius', 'B: Augustus', 'C: Marcus Aurelius'], 1);
const questions = [q1, q2, q3];
let runningQuestion;
let gamePlaying;
init()
document.querySelector('.button1').addEventListener('click', nextQuestion)
function nextQuestion(e) {
console.log(e.target)
if (gamePlaying === true && runningQuestion <= questions.length - 1) {
clearAnswers()
document.querySelector('.button1').textContent = 'Next Question'
runningQuestion++
questions[runningQuestion].displayAnswers()
}
if (runningQuestion >= questions.length - 1) {
document.querySelector('.button1').textContent = 'Try again!'
runningQuestion = 0
}
}
function clearAnswers() {
document.querySelectorAll('.name').forEach(el => {
el.remove()
})
}
document.querySelector('.button2').addEventListener('click', resetGame)
function resetGame() {
document.querySelector('.button1').textContent = 'Next Question'
clearAnswers()
runningQuestion = 0
questions[runningQuestion].displayAnswers()
}
function init() {
gamePlaying = true;
runningQuestion = 0;
questions[runningQuestion].displayAnswers()
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.container {
display: flex;
width: 400px;
height: auto;
margin: 100px auto;
align-items: center;
flex-direction: column;
}
.question {
margin-top: 40px;
color: rgb(102, 0, 0);
font-size: 1.4rem;
}
.answers {
display: flex;
flex-direction: column;
margin-top: 10px;
height: 100px;
margin-bottom: 15px;
}
.name {
margin-top: 20px;
cursor: pointer;
color: rgb(102, 0, 0);
font-size: 1.2rem;
}
.button1 {
margin-top: 50px;
border-style: none;
width: 350px;
height: 50px;
font-size: 1.4rem;
}
ul>li {
list-style-type: none;
margin-top: 10px;
font-size: 1.2rem;
color: rgb(102, 0, 0);
height: 30px;
cursor: pointer;
display: block;
}
.button2 {
margin-top: 20px;
border-style: none;
width: 350px;
height: 50px;
font-size: 1.4rem;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Quiz</title>
</head>
<body>
<div class="container">
<div class="question"></div>
<div class="answers"></div>
<button type="button" class="button1">Next Question</button>
<button type="button" class="button2">Reset</button>
</div>
<script src="app.js"></script>
</body>
</html>
The problem with the current version is that you reset runningQuestion to 0, and when clicking on the button, you execute nextQuestion, which, as the name implies, goes to the next question (runningQuestion++).
I see 2 ways of solving this. Either the "easy" way, by resetting runningQuestion to -1 so that it goes to 0:
class Question{constructor(e,s,t){this.question=e,this.answers=s,this.correct=t}displayAnswers(){document.querySelector(".question").innerHTML=`<div class="q1">${this.question}</div>`;let e=0,s=this.answers;for(let t of s){let s=`<div class="name" id=${e}>${t}</div>`;document.querySelector(".answers").insertAdjacentHTML("beforeend",s),e++}}}const q1=new Question("What's the capitol of Rwanda?",["A: Dodoma","B: Acra","C: Kigali"],2),q2=new Question("What's is the square root of 0?",["A: Not possible","B: 0","C: 1"],1),q3=new Question("Who was Rome's first emperor?",["A: Tiberius","B: Augustus","C: Marcus Aurelius"],1),questions=[q1,q2,q3];let runningQuestion,gamePlaying;init(),document.querySelector(".button1").addEventListener("click",nextQuestion);
/* Nothing changed above */
function nextQuestion(e) {
runningQuestion++; // <---------------------------------------------------------
if (gamePlaying === true && runningQuestion <= questions.length - 1) {
clearAnswers();
document.querySelector('.button1').textContent = 'Next Question';
questions[runningQuestion].displayAnswers();
}
if (runningQuestion >= questions.length - 1) {
document.querySelector('.button1').textContent = 'Try again!';
runningQuestion = -1; // <-----------------------------------------------------
}
}
/* Nothing changed below */
function clearAnswers(){document.querySelectorAll(".name").forEach(e=>{e.remove()})}function resetGame(){document.querySelector(".button1").textContent="Next Question",clearAnswers(),runningQuestion=0,questions[runningQuestion].displayAnswers()}function init(){gamePlaying=!0,runningQuestion=0,questions[runningQuestion].displayAnswers()}document.querySelector(".button2").addEventListener("click",resetGame);
/* Same CSS as yours */ *{box-sizing:border-box;margin:0;padding:0}.container{display:flex;width:400px;height:auto;margin:100px auto;align-items:center;flex-direction:column}.question{margin-top:40px;color:#600;font-size:1.4rem}.answers{display:flex;flex-direction:column;margin-top:10px;height:100px;margin-bottom:15px}.name{margin-top:20px;cursor:pointer;color:#600;font-size:1.2rem}.button1{margin-top:50px;border-style:none;width:350px;height:50px;font-size:1.4rem}ul>li{list-style-type:none;margin-top:10px;font-size:1.2rem;color:#600;height:30px;cursor:pointer;display:block}.button2{margin-top:20px;border-style:none;width:350px;height:50px;font-size:1.4rem}
<!-- Same HTML as yours --> <div class="container"> <div class="question"></div><div class="answers"></div><button type="button" class="button1">Next Question</button> <button type="button" class="button2">Reset</button></div>
or another way, which I find cleaner. A problem you can run into with your current code, is that if you have other things to keep track of, like a score, for example, you might forget to reset them as well, inside your nextQuestion function. And if you add other stuff, you'll need to reset them in multiple places in your code.
What I would do is simply reuse the resetGame function to reset everything:
class Question{constructor(e,s,t){this.question=e,this.answers=s,this.correct=t}displayAnswers(){document.querySelector(".question").innerHTML=`<div class="q1">${this.question}</div>`;let e=0,s=this.answers;for(let t of s){let s=`<div class="name" id=${e}>${t}</div>`;document.querySelector(".answers").insertAdjacentHTML("beforeend",s),e++}}}const q1=new Question("What's the capitol of Rwanda?",["A: Dodoma","B: Acra","C: Kigali"],2),q2=new Question("What's is the square root of 0?",["A: Not possible","B: 0","C: 1"],1),q3=new Question("Who was Rome's first emperor?",["A: Tiberius","B: Augustus","C: Marcus Aurelius"],1),questions=[q1,q2,q3];let runningQuestion,gamePlaying;
/* Nothing changed above */
const btn1 = document.querySelector('.button1');
init();
btn1.addEventListener("click", onButtonClick);
function isLastQuestion() { return runningQuestion >= questions.length - 1; }
function onButtonClick() {
if (gamePlaying === true && !isLastQuestion()) {
runningQuestion++;
displayQuestion();
} else {
resetGame();
}
}
function displayQuestion() {
clearAnswers();
btn1.textContent = isLastQuestion() ? 'Try again' : 'Next Question';
questions[runningQuestion].displayAnswers();
}
/* Nothing changed below */
function clearAnswers(){document.querySelectorAll(".name").forEach(e=>{e.remove()})}function resetGame(){document.querySelector(".button1").textContent="Next Question",clearAnswers(),runningQuestion=0,questions[runningQuestion].displayAnswers()}function init(){gamePlaying=!0,runningQuestion=0,questions[runningQuestion].displayAnswers()}document.querySelector(".button2").addEventListener("click",resetGame);function init(){gamePlaying=true;runningQuestion = 0;questions[runningQuestion].displayAnswers()}
/* Same CSS as yours */ *{box-sizing:border-box;margin:0;padding:0}.container{display:flex;width:400px;height:auto;margin:100px auto;align-items:center;flex-direction:column}.question{margin-top:40px;color:#600;font-size:1.4rem}.answers{display:flex;flex-direction:column;margin-top:10px;height:100px;margin-bottom:15px}.name{margin-top:20px;cursor:pointer;color:#600;font-size:1.2rem}.button1{margin-top:50px;border-style:none;width:350px;height:50px;font-size:1.4rem}ul>li{list-style-type:none;margin-top:10px;font-size:1.2rem;color:#600;height:30px;cursor:pointer;display:block}.button2{margin-top:20px;border-style:none;width:350px;height:50px;font-size:1.4rem}
<!-- Same HTML as yours --> <div class="container"> <div class="question"></div><div class="answers"></div><button type="button" class="button1">Next Question</button> <button type="button" class="button2">Reset</button></div>

Categories