I don't understand why my pop-up isn't working - javascript

So I am currently working on a personal project but cannot get my modal to appear in the browser. I've tried researching it but I'm getting the same answers back that I am currently applying.
const open1 = document.getElementById('open1');
const modal_container = document.getElementById('modal_container');
const close1 = document.getElementById('close1');
open1.addEventListener('click', () => {
modal_container.classList.add('show');
});
close1.addEventListener('click', () => {
modal_container.classList.remove('show');
});
div.modal-container {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
background-color: rgba(0,0,0,0.3);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
}
.real45 {
background-color: #BC6C25;
border: 0;
border-radius: 25px;
color: #fff;
padding: 10px 25px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.real45:hover {
color: black;
}
.modal {
background-color: #fff;
width: 600px;
max-width: 100%;
padding: 30px;
border-style: solid;
border-radius: 25px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
text-align: center;
}
.modal h1 {
margin: 0;
}
.modal p {
opacity: 0.7;
}
.modal-container.show {
opacity: 1;
pointer-events: 1;
}
<button class="real45" id="open1"> Open Me </button>
<div class="modal-container" id="modal_container">
<div class="modal">
<h1> Modals are cool </h1>
<p> practice text </p>
<button class="real45" id="close1"> Close Me </button>
</div>
</div>
Please any and all suggestions are welcome I greatly appreciate it.

When you put pointer-events: none; on .modal-container, all child nodes will also inherit that property, which disables all pointer events (clicking, dragging, hovering, etc.).
So when you attempt to close the modal by clicking the button, nothing will happen.
I've added pointer-events: auto; to the .modal so that these events work for child nodes and you are able to close the modal.
const open1 = document.getElementById('open1');
const modal_container = document.getElementById('modal_container');
const close1 = document.getElementById('close1');
open1.addEventListener('click', () => {
modal_container.classList.add('show');
});
close1.addEventListener('click', () => {
modal_container.classList.remove('show');
});
div.modal-container {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
}
.real45 {
background-color: #BC6C25;
border: 0;
border-radius: 25px;
color: #fff;
padding: 10px 25px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.real45:hover {
color: black;
}
.modal {
background-color: #fff;
width: 600px;
max-width: 100%;
padding: 30px;
border-style: solid;
border-radius: 25px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
text-align: center;
position: relative;
pointer-events: auto;
}
.modal h1 {
margin: 0;
}
.modal p {
opacity: 0.7;
}
.modal-container.show {
opacity: 1;
pointer-events: 1;
}
<button id="open1">open
</button>
<div class="modal-container" id="modal_container">
<div class="modal">
<h1> Modals are cool </h1>
<p> practice text </p>
<button class="real45" id="close1"> Close Me </button>
</div>
</div>

I needed to add my <script> below my <button> and <div> tags. This is the correct way to make it work in browser.
<button class="real45" id="open1"> Open Me </button>
<div class="modal-container" id="modal_container">
<div class="modal">
<h1> Modals are cool </h1>
<p> practice text </p>
<button class="real45" id="close1"> Exit </button>
</div>
</div>
<script>
const open1 = document.getElementById("open1");
const modal_container = document.getElementById("modal_container");
const close1 = document.getElementById("close1");
open1.addEventListener("click", () => {
modal_container.classList.add("show");
});
close1.addEventListener("click", () => {
modal_container.classList.remove("show");
});
</script>

Related

Displaying popups based on the user buttons selection

What I want to do here is whenever the user selects their choice of a specific component a corresponding popup is displayed according to the selected buttons/choices.
But, so far I couldn't bind the specific buttons as well as the I keep getting the two popups whenever I press the recommended button
basically, I'm trying to do something like this
Here's my code:
//choices buttons
const mainbtnEL_1 = document.querySelectorAll(".btn__001");
mainbtnEL_1.forEach(btnEl => {
btnEl.addEventListener("click", () => {
document.querySelector('.special__1')?.classList.remove('special__1');
btnEl.classList.add('special__1');
});
});
const mainbtnEL_2 = document.querySelectorAll(".btn__002");
mainbtnEL_2.forEach(btnEl => {
btnEl.addEventListener("click", () => {
document.querySelector('.special__2')?.classList.remove('special__2');
btnEl.classList.add('special__2');
});
});
//pop up
function open__Popup() {
popup.classList.add('open-Popup');
}
function close__Popup() {
popup.classList.remove('open-Popup');
}
let popup__2 = document.getElementById("popup__2");
function open__Popup2() {
popup__2.classList.add('open-Popup');
}
function close__Popup2() {
popup__2.classList.remove('open-Popup');
}
.special__1 {
background-color: #4837ff;
}
.special__2 {
background-color: #4837ff;
}
.popup {
display: grid;
grid-template-columns: 1fr 1fr;
width: 800px;
max-width: 800px;
background: #FFF;
border-radius: 6px;
position: relative;
bottom: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.1);
text-align: center;
justify-content: center;
padding: 0 30px 30px;
color: #333;
align-items: center;
justify-self: center;
margin: 0 auto;
height: 50vh;
z-index: 1;
visibility: hidden;
transition: transform 0.4s ease;
}
.open-Popup {
visibility: visible;
transform: translate(-50%, -50%) scale(1);
}
.table__1 {
font-family: arial, sans-serif;
width: 100%;
height: 50%;
background: #fff;
border-collapse: collapse;
}
td,
th {
border: 1px solid #acacac;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
.main__img_1 {
width: 400px;
margin-top: 20px;
border-radius: 50%;
box-shadow: 0 2px 4px rgba(8, 218, 255, 0.6);
}
.close__btn {
position: relative;
width: 50%;
margin-top: 20px;
left: 80px;
background: hsla(204, 100%, 15%, 0.286);
color: #fff;
border: 0;
outline: none;
font-size: 18px;
border-radius: 4px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
<h2> Choose your CPU </h2>
<div class="mainbtn__1">
<button type="button" class="btn__001" id="AMD">AMD</button>
<button type="button" class="btn__001" id="Intel">Intel</button>
</div>
<h2> Choose your GPU </h2>
<div class="mainbtn__2">
<button type="button" class="btn__002" id="RTX3060">RTX3060</button>
<button type="button" class="btn__002" id="RTX3050">RTX3050</button>
</div>
<div class="popup__container">
<button type="submit" class="popup__btn" id="recommended" onclick="open__Popup(); open__Popup2()">Recommended</button>
<!-- FIRST popup page -->
<div class="popup" id="popup">
<table class="table__1" id="tb_1">
<tr>
<td>CPU</td>
<td>AMD</td>
</tr>
<tr>
<td>GPU</td>
<td>RTX3060</td>
</tr>
</table>"
<button type="button" class="close__btn" onclick="close__Popup()">Close</button>
</div>
<!-- second popup page -->
<div class="popup" id="popup__2">
<table class="table__1" id="tb_2">
<tr>
<td>CPU</td>
<td>Intel</td>
</tr>
<tr>
<td>GPU</td>
<td>RTX3050</td>
</tr>
</table>"
<button type="button" class="close__btn" onclick="close__Popup2()">Close</button>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<script src="app.js"></script>
And the answer to this is always: Delegate
the button names and classes made is non-trivial to add and remove the special__ classes
const choices = document.getElementById("choices");
const buttons = choices.querySelectorAll("button");
const popupContainer = document.querySelector(".popup__container");
const recommend = document.getElementById("recommended");
//choices buttons
choices.addEventListener("click", (e) => {
const tgt = e.target;
if (!tgt.matches("button")) return;
const whichButton = tgt.dataset.target.replace("popup","")
tgt.classList.add(`special__${whichButton}`);
// document.getElementById(tgt.dataset.target).classList.add('open-Popup');
});
// close
popupContainer.addEventListener("click", (e) => {
const tgt = e.target;
if (!tgt.matches(".close__btn")) return;
const parentPopup = tgt.closest("div.popup");
const id = parentPopup.id;
parentPopup.classList.remove('open-Popup');
const sourceButton = `[data-target=${id}]`;
const className = `special__${id.replace("popup","")}`;
document.querySelectorAll(sourceButton).forEach(button => button.classList.remove(className))
});
recommend.addEventListener("click", () => {
// document.querySelectorAll(".popup").forEach(popup => popup.classList.add("open-Popup"));
choices.querySelectorAll("button")
.forEach(button => [...button.classList.entries()] // the buttons classes
.forEach(([_,cls]) => {
if (cls.startsWith("special__")) { // it was selected
document.getElementById(button.dataset.target).classList.add('open-Popup');
}
})
);
});
.special__1 {
background-color: #4837ff;
}
.special__2 {
background-color: #4837ff;
}
.popup {
display: grid;
grid-template-columns: 1fr 1fr;
width: 800px;
max-width: 800px;
background: #FFF;
border-radius: 6px;
position: relative;
bottom: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.1);
text-align: center;
justify-content: center;
padding: 0 30px 30px;
color: #333;
align-items: center;
justify-self: center;
margin: 0 auto;
height: 50vh;
z-index: 1;
visibility: hidden;
transition: transform 0.4s ease;
}
.open-Popup {
visibility: visible;
transform: translate(-50%, -50%) scale(1);
}
.table__1 {
font-family: arial, sans-serif;
width: 100%;
height: 50%;
background: #fff;
border-collapse: collapse;
}
td,
th {
border: 1px solid #acacac;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
.main__img_1 {
width: 400px;
margin-top: 20px;
border-radius: 50%;
box-shadow: 0 2px 4px rgba(8, 218, 255, 0.6);
}
.close__btn {
position: relative;
width: 50%;
margin-top: 20px;
left: 80px;
background: hsla(204, 100%, 15%, 0.286);
color: #fff;
border: 0;
outline: none;
font-size: 18px;
border-radius: 4px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
<div id="choices">
<h2> Choose your CPU </h2>
<div class="mainbtn__1">
<button type="button" class="btn__001" id="AMD" data-target="popup1">AMD</button>
<button type="button" class="btn__001" id="Intel" data-target="popup2">Intel</button>
</div>
<h2> Choose your GPU </h2>
<div class="mainbtn__2">
<button type="button" class="btn__002" id="RTX3060" data-target="popup1">RTX3060</button>
<button type="button" class="btn__002" id="RTX3050" data-target="popup2">RTX3050</button>
</div>
</div>
<div class="popup__container">
<button type="submit" class="popup__btn" id="recommended">Recommended</button>
<!-- FIRST popup page -->
<div class="popup" id="popup1">
<table class="table__1" id="tb_1">
<tr>
<td>CPU</td>
<td>AMD</td>
</tr>
<tr>
<td>GPU</td>
<td>RTX3060</td>
</tr>
</table>
<button type="button" class="close__btn">Close</button>
</div>
<!-- second popup page -->
<div class="popup" id="popup2">
<table class="table__1" id="tb_2">
<tr>
<td>CPU</td>
<td>Intel</td>
</tr>
<tr>
<td>GPU</td>
<td>RTX3050</td>
</tr>
</table>
<button type="button" class="close__btn">Close</button>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<script src="app.js"></script>

Local storage data not saving on page refresh

I am creating a settings portion on a website. I want the features chosen to be "saved" and kept when the page refreshes. I attempted this but it seems to just reset the form when I refresh the page. Another issue is when I click on the cancel button, the toggle buttons reset but the dropdown comes back blank instead of going back to the placeholder "select timezone". The issue most likely lies in my javascript code below. It's also throwing an error in stack overflow but works properly on my website (minus the issues described above). Any suggestions would be much appreciated!
// ---------- TOGGLE BTN ----------
const toggle = document.getElementsByClassName("toggle");
const labels = document.getElementsByClassName("labels");
for(let i=0; i < 2; i++) {
labels[i].innerHTML = "OFF";
toggle[i].addEventListener( "click", () => {
if(labels[i].innerHTML == "OFF") {
// console.log("button toggled");
labels[i].classList.add("on");
labels[i].innerHTML= "ON";
} else {
labels[i].classList.remove("on");
labels[i].innerHTML = "OFF";
}
});
}
// ---------- LOCAL STORAGE DATA ----------
const save = document.getElementById("save");
const cancel = document.getElementById("cancel");
const emailBtn = document.getElementById("togBtn");
const publicBtn = document.getElementById("togBtn2");
const zone = document.getElementById("timezone");
// emailBtn.value = data;
// publicBtn.value = data;
// zone.value = data;
const data = {
email: emailBtn.value,
privacy: publicBtn.value,
timezone: zone.value
}
var emailVal = localStorage.getItem("email");
var privacyVal = localStorage.getItem("privacy");
var zoneVal = localStorage.getItem("timezone");
save.addEventListener('click', () => {
localStorage.setItem("email", emailBtn.value);
localStorage.setItem("privacy", publicBtn.value);
localStorage.setItem("timezone", zone.value);
});
cancel.addEventListener('click', () => {
localStorage.clear();
for(let i=0; i < 2; i++) {
labels[i].innerHTML = "OFF";
labels[i].classList.remove("on");
}
emailBtn.checked = false;
publicBtn.checked =false;
zone.value = 'Select Timezone';
});
.settings {
padding-left: 15px;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
.settings h3 {
flex-basis: 100%;
}
.button1,
.button2 {
flex-basis: 100%;
display: flex;
align-items:center;
}
label {
flex-basis: 90%;
}
input {
flex-basis: 10%;
}
.form-field {
flex-basis: 100%;
background-color: rgb(241, 240, 240);
border: 1px solid lightgrey;
color: grey;
border-radius: 5px;
padding: 10px;
margin: 0 15px 10px 0;
}
.settings-button {
display: flex;
justify-content: center;
}
button {
margin: 10px 15px 10px 0;
padding: 10px;
border: 1px solid lightgrey;
border-radius: 5px;
}
#save,
#cancel {
flex-basis: 50%;
}
#save {
background-color: #7477BF;
color: white;
}
#cancel {
background-color: darkgray;
color: white;
}
#timezone {
margin-top:25px;
}
/* toggle button */
.toggle {
-webkit-appearance: none;
-webkit-tap-highlight-color: transparent;
position: relative;
outline: 0;
cursor: pointer;
margin: 10px 15px;
}
.toggle:after {
content: '';
width: 80px;
height: 28px;
display: inline-block;
background: rgba(196, 195, 195, 0.55);
border: 2px solid rgba(196, 195, 195, 0.55);
border-radius: 18px;
clear: both;
}
.toggle:before {
content: '';
width: 20px;
height: 20px;
display: block;
position: absolute;
top: 3px;
/* left: 0;
top: -3px; */
border: 2px solid rgba(196, 195, 195, 0.55);
border-radius: 50%;
background: rgb(255, 255, 255);
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6);
}
.toggle:checked:before {
left: 54px;
box-shadow: -1px 1px 3px rgba(0, 0, 0, 0.6);
}
.toggle:checked:after {
background: #7477BF;
}
.toggle,
.toggle:before,
.toggle:after,
.toggle:checked:before,
.toggle:checked:after {
transition: ease .4s;
-webkit-transition: ease .4s;
-moz-transition: ease .4s;
-o-transition: ease .4s;
}
.labels {
color: gray;
position: relative;
font-size: 15px;
transform: translate(-48px, -3px);
}
.on {
color: white;
transform: translate(-90px, -3px);
}
<section class="settings" id="settings">
<h3>Settings</h3>
<!-- custom CSS toggle code-->
<div class="button1">
<label for="togBtn">Send Email Notfications </label>
<input type="checkbox" class="toggle" id="togBtn">
<span class="labels"></span>
</div>
<div class="button2">
<label for="togBtn2">Set Profile to Public </label>
<input type="checkbox" class="toggle" id="togBtn2">
<span class="labels"></span>
</div>
<select class="form-field" id="timezone">
<option disabled selected>Select a Timezone</option>
<option>Eastern</option>
<option>Western</option>
<!-- more options -->
</select>
<div class="settings-button" >
<button class="button-primary" id="save">Save</button>
<button class="button-disabled" id="cancel">Cancel</button>
</div>
</section>
here a working example.
The problems with your code were that you were using emailBtn.value and publicBtn.value instead of emailBtn.checked and publicBtn.checked (they are checkbox so in order to get the correct value you have to read che checked property) and you were not loading the saved values on document load (the function inside window.addEventListener("load", ...) in my example.
Hope this helps you.

How to create a button in following style?

I want to create two button which will float next to each other and also when we click one of them it will change background-color to #474e5d and some shadow effect. I am very new to design please help me to do this.
Click here to see the button design
//js
const span2 = document.getElementById("span2")
const span1 = document.getElementById("span1")
span2.addEventListener("click",function ( ) {
const span3 = document.getElementById("span3")
span3.style.left="150px"
span3.innerHTML="Search by dictric"
span3.style.transition = "all 0.5s";
})
span1.addEventListener("click",function () {
const span3 = document.getElementById("span3")
span3.style.left="0px"
span3.innerHTML="Search by pin code"
span3.style.transition = "all 0.5s";
})
/* css */
.sld_btn{
display: flex;
width: 300px;
height: 40px;
border-radius: 25px;
position: relative;
background-color: rgb(102, 102, 102);
}
.sld_btn span{
width: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 0.5;
}
#span3{
border-radius: 25px;
position: absolute;
height: 100%;
width:150px ;
background-color: rgb(151, 151, 151);
box-shadow: 5px 5px 5px rgba(41, 41, 41, 0.5);
}
<!-- HTML -->
<div class="sld_btn">
<span class="span1" id="span1">Search by pin code</span>
<span id="span2">Search by dictric</span>
<span class="span3" id="span3">Search by pin code</span>
</div>
I think this is close to what you are looking for. I can explain individual parts if you want.
Click on Run Code Snippet to see it working.
const buttons = document.querySelectorAll('.button');
function onButtonClick(event) {
for (button of buttons) button.classList.remove('clickedButton');
event.target.classList.add('clickedButton');
}
.container {
display: flex;
border-radius: 32px;
background-color: grey;
width: max-content;
}
.button {
cursor: pointer;
padding: 16px;
text-align: center;
border-radius: 32px;
font-size: 14px;
transition: all 0.25s ease;
}
.clickedButton {
background-color: #474e5d;
box-shadow: 0px 0px 15px #444;
color: white;
}
<div class="container">
<div class="button" onclick="onButtonClick(event)">Search by Pin Code</div>
<div class="button" onclick="onButtonClick(event)">Search by District</div>
</div>

QuerySelectorAll won't work for shuffling the order of that list

I'm building a card flip matching game. Rather than having the card flip on a mouse click, I want keyboard controls.
I'm having trouble getting the cards to shuffle. The cards will shuffle fine if I use the 'selector' class from the DOM, but I plan to use those as a highlighter/selector icon when then user is toggling through the cards. So I need the cards themselves to shuffle.
Don't mind that most of this code is tailored for clicking with a mouse. I'm still in the middle of modifying it and I need to first be able to shuffle the cards and leave the selector classes.
Here is a snippet of my HTML:
<section class='gameContainer'>
<div class='game'>
<div class='row'>
<div class='selector'>
<div class='card' data-framework='star'>
<img class='frontSide'src='https://drive.google.com/uc?export=view&id=1A_zvQyMfZtwBqiVbYifebM07R15dUVD-'>
<img class='backSide'src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
<div class='selector'>
<div class='card' data-framework='mushroom'>
<img class='frontSide'src='https://drive.google.com/uc?export=view&id=1VgbaVqfGrAw_RefRbMpaKNW4yuQRA5Lm'>
<img class='backSide'src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
<div class='selector'>
<div class='card' data-framework='flower'>
<img class='frontSide'src='https://drive.google.com/uc?export=view&id=1Vae7dDSTQmvFlW0hoODvud_Y8_m-VVJk'>
<img class='backSide'src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
<div class='selector'>
<div class='card' data-framework='coinTen'>
<img class='imageWithNum'src='https://drive.google.com/uc?export=view&id=1aTtc4B_GK_EbUyk6Uhl2HFh7uZrZLahr'>
<img class='backSide'src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
<div class='selector'>
<div class='card' data-framework='chest'>
<img class='imageWithNum'src='https://drive.google.com/uc?export=view&id=1CYWq7iEShB2YG3bQPUCbihsW9_vzgEL_'>
<img class='backSide' src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
<div class='selector'>
<div class='card' data-framework='mushroom'>
<img class='frontSide'src='https://drive.google.com/uc?export=view&id=1VgbaVqfGrAw_RefRbMpaKNW4yuQRA5Lm'>
<img class='backSide' src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
</div>
</div>
</section>
Here is my CSS:
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
height: 100vh;
background-color: #000;
}
#titleContainer {
border: solid 0px red;
width: 50%;
margin: auto;
background-color: #ffe400;
padding: 20px;
}
#title1 {
font-family: '8BITWONDERNominal';
font-weight: normal;
font-style: normal;
color: #1f57b8;
text-align: center;
text-shadow: 1px 2px 0px #ff0000;
}
#title2 {
font-family: '8BITWONDERNominal';
font-weight: normal;
font-style: normal;
text-align: center;
color: #ff0000;
text-shadow: 1px 2px 0px #000;
}
.gameContainer {
border: solid 1px black;
background: repeating-linear-gradient(
-45deg,
#fff,
#fff 10px,
#b30000 10px,
#b30000 20px
);
width: 640px;
height: 500px;
margin: auto;
display: flex;
justify-content: center;
align-items: center;
}
.game {
background-color: #000;
width: 90%;
height: 90%;
}
.row {
border: solid 0px red;
width: 100%;
height: 33.333%;
display: flex;
justify-content: space-around;
align-items: center;
padding: 20px;
perspective: 1000px;
}
.selector, .selectorActive {
box-sizing: content-box;
border: solid 8px black;
border-radius: 6px;
position: relative;
width: 15%;
height: 110%;
display: flex;
justify-content: center;
align-items: center;
}
.selectorActive {
border: solid 8px orange;
}
.card {
border: solid 0px aqua;
position: absolute;
display: flex;
width: 90%;
height: 89%;
transform-style: preserve-3d;
transition: transform .5s;
}
.card.flip {
transform: rotateY(180deg);
}
.frontSide, .backSide{
border: solid 0px deeppink;
position: absolute;
width: 100%;
height: 100%;
padding: 24px 9px;
background-color: #ffd1d1;
backface-visibility: hidden;
}
.frontSide {
transform: rotateY(180deg);
}
.imageWithNum {
border: solid 0px deeppink;
position: absolute;
width: 100%;
height: 100%;
padding: 29px 14px 0px;
background-color: #ffd1d1;
backface-visibility: hidden;
transform: rotateY(180deg);
}
.backSide {
background-color: #fff;
}
.cardSelector {
border: solid 8px #ff7b00;
}
Here is my JavaScript. I grab the card classes at the beginning of the script, then at the end there's the shuffle function. Also, don't mind that the For loop starts at 1 rather than 0. That was intended:
const cards = document.querySelectorAll('.card');
let hasFlippedCard = false;
let lockBoard = false;
let firstCard, secondCard;
function flipCard(){
// This will disable any clicks that occur before the non-matched cards reset
if(lockBoard)
return;
// This will prevent a double click on the same card to obtain a match
if(this === firstCard)
return;
this.classList.add('flip');
if(!hasFlippedCard){
// First card is clicked
hasFlippedCard = true;
firstCard = this;
return;
}
// Second card is clicked
secondCard = this;
// Check if cards match
checkForMatch();
}
//This function will check if the two cards chosen match
function checkForMatch(){
let isMatch = firstCard.dataset.framework === secondCard.dataset.framework;
isMatch ? disableCards() : unflipCards();
}
//This function will disable the chosen cards whenever there's a match
function disableCards(){
firstCard.removeEventListener('click', flipCard);
secondCard.removeEventListener('click', flipCard);
resetBoard();
}
//This function will reset the cards if they don't match
function unflipCards(){
lockBoard = true;
setTimeout(() => {
firstCard.classList.remove('flip');
secondCard.classList.remove('flip');
resetBoard();
}, 1500);
}
function resetBoard(){
[hasFlippedCard, lockBoard] = [false, false];
[firstCard, secondCard] = [null, null];
}
(function shuffle(){
for(let x = 1; x < cards.length; x++){
let randomPos = Math.floor(Math.random() * 17);
cards[x].style.order = randomPos;
}
})();
cards.forEach(card => card.addEventListener('click', flipCard));
Also yes, I'm trying to recreate the card flip game from Super Mario Bros. 3. :D
When you specify the order, it applies to the child of the flex container. According to the specification:
The contents of a flex container consists of zero or more flex items:
each child of a flex container becomes a flex item.
Your .card elements do not appear to be children of the flex container. They're descendants of it, but they're children of the .selector elements. If you apply the ordering to the elements with the selector class, I think it should work.
Note that your first card will always be the star, since you're starting your for loop at x = 1. This may be intentional, but I just wanted to point it out.
const cards = document.querySelectorAll('.card');
let hasFlippedCard = false;
let lockBoard = false;
let firstCard, secondCard;
function flipCard() {
// This will disable any clicks that occur before the non-matched cards reset
if (lockBoard)
return;
// This will prevent a double click on the same card to obtain a match
if (this === firstCard)
return;
this.classList.add('flip');
if (!hasFlippedCard) {
// First card is clicked
hasFlippedCard = true;
firstCard = this;
return;
}
// Second card is clicked
secondCard = this;
// Check if cards match
checkForMatch();
}
//This function will check if the two cards chosen match
function checkForMatch() {
let isMatch = firstCard.dataset.framework === secondCard.dataset.framework;
isMatch ? disableCards() : unflipCards();
}
//This function will disable the chosen cards whenever there's a match
function disableCards() {
firstCard.removeEventListener('click', flipCard);
secondCard.removeEventListener('click', flipCard);
resetBoard();
}
//This function will reset the cards if they don't match
function unflipCards() {
lockBoard = true;
setTimeout(() => {
firstCard.classList.remove('flip');
secondCard.classList.remove('flip');
resetBoard();
}, 1500);
}
function resetBoard() {
[hasFlippedCard, lockBoard] = [false, false];
[firstCard, secondCard] = [null, null];
}
(function shuffle() {
let s = document.querySelectorAll(".selector");
for (let x = 1; x < s.length; x++) {
let randomPos = Math.floor(Math.random() * 17);
s[x].style.order = randomPos;
}
})();
cards.forEach(card => card.addEventListener('click', flipCard));
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
height: 100vh;
background-color: #000;
}
#titleContainer {
border: solid 0px red;
width: 50%;
margin: auto;
background-color: #ffe400;
padding: 20px;
}
#title1 {
font-family: '8BITWONDERNominal';
font-weight: normal;
font-style: normal;
color: #1f57b8;
text-align: center;
text-shadow: 1px 2px 0px #ff0000;
}
#title2 {
font-family: '8BITWONDERNominal';
font-weight: normal;
font-style: normal;
text-align: center;
color: #ff0000;
text-shadow: 1px 2px 0px #000;
}
.gameContainer {
border: solid 1px black;
background: repeating-linear-gradient( -45deg, #fff, #fff 10px, #b30000 10px, #b30000 20px);
width: 640px;
height: 500px;
margin: auto;
display: flex;
justify-content: center;
align-items: center;
}
.game {
background-color: #000;
width: 90%;
height: 90%;
}
.row {
border: solid 0px red;
width: 100%;
height: 33.333%;
display: flex;
justify-content: space-around;
align-items: center;
padding: 20px;
perspective: 1000px;
}
.selector,
.selectorActive {
box-sizing: content-box;
border: solid 8px black;
border-radius: 6px;
position: relative;
width: 15%;
height: 110%;
display: flex;
justify-content: center;
align-items: center;
}
.selectorActive {
border: solid 8px orange;
}
.card {
border: solid 0px aqua;
position: absolute;
display: flex;
width: 90%;
height: 89%;
transform-style: preserve-3d;
transition: transform .5s;
}
.card.flip {
transform: rotateY(180deg);
}
.frontSide,
.backSide {
border: solid 0px deeppink;
position: absolute;
width: 100%;
height: 100%;
padding: 24px 9px;
background-color: #ffd1d1;
backface-visibility: hidden;
}
.frontSide {
transform: rotateY(180deg);
}
.imageWithNum {
border: solid 0px deeppink;
position: absolute;
width: 100%;
height: 100%;
padding: 29px 14px 0px;
background-color: #ffd1d1;
backface-visibility: hidden;
transform: rotateY(180deg);
}
.backSide {
background-color: #fff;
}
.cardSelector {
border: solid 8px #ff7b00;
}
<section class='gameContainer'>
<div class='game'>
<div class='row'>
<div class='selector'>
<div class='card' data-framework='star'>
<img class='frontSide' src='https://drive.google.com/uc?export=view&id=1A_zvQyMfZtwBqiVbYifebM07R15dUVD-'>
<img class='backSide' src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
<div class='selector'>
<div class='card' data-framework='mushroom'>
<img class='frontSide' src='https://drive.google.com/uc?export=view&id=1VgbaVqfGrAw_RefRbMpaKNW4yuQRA5Lm'>
<img class='backSide' src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
<div class='selector'>
<div class='card' data-framework='flower'>
<img class='frontSide' src='https://drive.google.com/uc?export=view&id=1Vae7dDSTQmvFlW0hoODvud_Y8_m-VVJk'>
<img class='backSide' src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
<div class='selector'>
<div class='card' data-framework='coinTen'>
<img class='imageWithNum' src='https://drive.google.com/uc?export=view&id=1aTtc4B_GK_EbUyk6Uhl2HFh7uZrZLahr'>
<img class='backSide' src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
<div class='selector'>
<div class='card' data-framework='chest'>
<img class='imageWithNum' src='https://drive.google.com/uc?export=view&id=1CYWq7iEShB2YG3bQPUCbihsW9_vzgEL_'>
<img class='backSide' src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
<div class='selector'>
<div class='card' data-framework='mushroom'>
<img class='frontSide' src='https://drive.google.com/uc?export=view&id=1VgbaVqfGrAw_RefRbMpaKNW4yuQRA5Lm'>
<img class='backSide' src='https://drive.google.com/uc?export=view&id=1YUCKsNqGAr81BMW1s8utU3zZFGzvm2uz'>
</div>
</div>
</div>
</div>
</section>

Javascript Stop Propagation

I have been trying to figure out how to get an index of a dynamically created element so that I can write a function to delete it (splice).
I have figured out how to get the index really manually, but the problem is that I am getting Propagation from my event delegation and I am not sure how to stop it.
I have tried putting stopPropagation(), preventDefault(), stopImmediatePropagation() at various points within the function and have spent the last hour reading around online trying to figure out how to stop it. I even tried setting the e.bubble to false with no avail.
Could someone point me in the right direction here? Im sure its my inexperience but I am just out of ideas as of now.
// Title of Question Set
const title = document.querySelector(".input_title-input");
// Array of Questions
const questions = [];
let chosen = [];
// Selected Question
let qChosen = [];
// Toggles if a new question is selected
let toggle = 0;
// Selecting Inputs and Button
let question = document.querySelector(".input_question-input");
let answer = document.querySelector(".input_answer-input");
let submit = document.querySelector(".input_submit-button");
let display = document.querySelector(".input_display");
let card = document.querySelector(".card_container");
let start = document.querySelector(".input_start-btn");
let guessInput = document.querySelector(".guess_input");
let submitGuess = document.querySelector(".submitGuess");
let nextQuestion = document.querySelector(".nextQuestion");
// Select all display items
let displayItems = document.getElementsByClassName("input_display-item");
// Select P quiz card values
let cardQuestion = document.querySelector(".quiz_question");
let cardAnswer = document.querySelector(".quiz_answer");
// Event Listener on Submit Button for Display Items Idividually
submit.addEventListener("click", function() {
if (question.value === "") {
question.classList.toggle("error");
answer.classList.toggle("error");
} else {
createObj();
let trashCan = createDisplayItem();
trashCan.addEventListener("click", function(e) {
console.log(this.parentNode);
console.log(questions);
console.log(e);
this.parentNode.remove();
});
inputReset();
toggle = questions.length;
start.removeAttribute("disabled");
}
});
start.addEventListener("click", function() {
console.log("clicked");
generateCard();
});
// Event Listener to test if guess is correct
submitGuess.addEventListener("click", function() {
if (guessInput.value.toLowerCase() === qChosen.answer.toLowerCase()) {
card.classList.toggle("flip");
submitGuess.disabled = true;
} else {
console.log("wrong or not working");
}
});
nextQuestion.addEventListener("click", function() {
card.classList.toggle("flip");
submitGuess.disabled = false;
setTimeout(generateCard, 1000);
});
// Create The object for inclusion to array
function createObj() {
let obj = {};
obj.question = question.value;
obj.answer = answer.value;
questions.push(obj);
}
// Resets inputs to blank after submit
function inputReset() {
question.value = "";
answer.value = "";
if (question.classList.contains("error")) {
question.classList.toggle("error");
answer.classList.toggle("error");
}
}
// Creates Each Display Item
function createDisplayItem() {
// Create new Div
let newUl = document.createElement("ul");
// Create Li and Image Elements
let liQuestion = document.createElement("li");
let liAnswer = document.createElement("li");
let trashCan = document.createElement("img");
// Set img src
trashCan.src = "../assets/trash.svg";
// Set classes
newUl.className = "input_display-item";
liQuestion.className = "input_display-question";
liAnswer.className = "input_display-answer";
trashCan.className = "input_display-delete";
// Set LI textContent
liQuestion.textContent = question.value;
liAnswer.textContent = answer.value;
// Append Children
display.appendChild(newUl);
newUl.appendChild(liQuestion);
newUl.appendChild(liAnswer);
return newUl.appendChild(trashCan);
}
//Generating Card Information per question
function generateCard() {
random();
if (toggle < 0) {
cardQuestion.textContent = "There are no more questions left";
cardAnswer.textContent = "There are no more questions left";
} else {
cardQuestion.textContent = qChosen.question;
cardAnswer.textContent = qChosen.answer;
}
}
// Choses a random value for the selection set
function random() {
if (questions.length === 0) {
toggle = -1;
} else {
let num = Math.floor(Math.random() * questions.length);
chosen = questions.splice(num, 1).concat(chosen);
qChosen = chosen[0];
}
}
// Notes
// I need to create a function that upon submit of a guess, checks its value against the answer textContent.
// I will likely need to make the text lowercase for the check to just make sure that they match exactly and that a capital letter wont create a false when its true.
/** Variables
---------------------------------------------------------*/
/** Reset
---------------------------------------------------------*/
* {
margin: 0;
padding: 0; }
*,
*::before,
*::after {
box-sizing: inherit; }
html {
box-sizing: border-box;
font-size: 62.5%; }
body {
font-weight: 400;
line-height: 1.5;
font-size: 2rem;
background-color: #bdbdc7; }
/** Primary Container
---------------------------------------------------------*/
.container {
max-width: 180rem;
display: flex; }
.flex {
display: flex;
justify-content: center;
align-items: center; }
.visible {
visibility: hidden; }
/** Input Section
---------------------------------------------------------*/
input[type="text"] {
padding: 0.5rem;
width: auto;
min-width: 100%;
line-height: 2rem; }
.input {
width: 40rem;
height: 100%;
padding: 1rem;
background-color: #ccc;
display: flex;
align-items: flex-start;
flex-direction: column; }
.input_title {
width: 100%;
display: flex;
flex-direction: column; }
.input_title-label {
display: flex;
justify-content: center; }
.input_title-input {
padding: 0.5rem; }
.input_question {
width: 100%;
display: flex;
flex-direction: column; }
.input_question-label {
display: flex;
justify-content: center; }
.input_question-input {
padding: 0.5rem; }
.input_answer {
width: 100%;
display: flex;
flex-direction: column; }
.input_answer-label {
display: flex;
justify-content: center; }
.input_answer-input {
padding: 0.5rem; }
.input_question-input.error, .input_answer-input.error {
border: 2px red solid; }
.input_submit {
width: 100%; }
.input_submit-button {
margin-top: 1rem;
padding: 0 1.5rem; }
.input_start {
width: 100%; }
.input_display {
width: 100%;
font-size: 1.5rem;
padding: 2rem 0 1rem 0; }
.input_display-item {
margin-bottom: 1rem;
padding: .2rem 2rem;
text-transform: capitalize;
background-color: #fff;
border-radius: 1rem;
list-style: none;
display: flex;
justify-content: space-between;
align-items: center; }
.input_display-item:nth-child(odd) {
background-color: #aaa;
border-radius: 1rem; }
.input_display-delete {
height: 1.8rem;
width: 1.8rem; }
.input :not(.input_display) div {
padding-bottom: 2rem; }
/** Quiz Card
---------------------------------------------------------*/
.card {
display: flex;
justify-content: center;
align-items: center;
width: 100%; }
.card_container {
transform-style: preserve-3d;
perspective: 1000px;
width: 60rem;
margin: 1rem;
cursor: pointer; }
.card_container .front {
transform: rotateY(0deg);
transform-style: preserve-3d; }
.card_container .front:after {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
content: "";
display: block;
opacity: 0.6;
background-color: #000;
backface-visibility: hidden;
border-radius: 10px; }
.card_container .back {
position: absolute;
top: 0;
left: 0;
width: 100%;
background-color: #cedce7;
background: linear-gradient(45deg, #dedce7 0%, #596a72 100%);
transform: rotateY(180deg);
transform-style: preserve-3d; }
.card_container .front,
.card_container .back {
background-color: red;
background-size: cover;
background-position: center;
transition: transform 0.7s cubic-bezier(0.4, 0.2, 0.2, 1);
transition: transform 0.7s cubic-bezier(0.4, 0.2, 0.2, 1);
backface-visibility: hidden;
text-align: center;
min-height: 500px;
height: auto;
border-radius: 10px;
color: #fff;
font-size: 1.5rem; }
.flip {
transition: transform 0.7s cubic-bezier(0.4, 0.2, 0.2, 1);
transition: transform 0.7s cubic-bezier(0.4, 0.2, 0.2, 1); }
.flip .back {
transform: rotateY(0deg);
transform-style: preserve-3d; }
.flip .front {
transform: rotateY(-180deg);
transform-style: preserve-3d; }
.inner {
transform: translateY(-50%) translateZ(60px) scale(0.94);
top: 50%;
position: absolute;
left: 0;
width: 100%;
padding: 2rem;
box-sizing: border-box;
outline: 1px solid transparent;
perspective: inherit;
z-index: 2; }
.front .inner p {
font-size: 2rem;
margin-bottom: 2rem;
position: relative; }
.card_container-guess {
padding-top: 2rem; }
.card_container-guess .guess_input {
width: 2rem;
margin: 1rem auto;
padding: 1rem;
border-radius: 1rem;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.55), 0px 1px 1px rgba(255, 255, 255, 0.5);
border: 1px solid #666;
opacity: 0.6; }
.card_container-guess .guess_input:hover, .card_container-guess .guess_input:focus {
opacity: .8;
color: #08c;
box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25), inset 0px 3px 6px rgba(0, 0, 0, 0.25); }
.btnNew {
height: 5rem;
width: 12rem;
margin: 1.5rem 3rem 1rem 0;
font-weight: 700;
color: #333;
background-image: linear-gradient(top, #f4f1ee, #fff);
box-shadow: 0px 8px 30px 1px rgba(0, 0, 0, 0.3), inset 0px 4px 1px 1px white, inset 0px -3px 1px 1px rgba(204, 198, 197, 0.5);
border-radius: 5%;
position: relative;
transition: all .1s linear;
outline: none; }
.btnNew:after {
color: #e9e6e4;
content: "";
display: block;
font-size: 30px;
height: 3rem;
text-decoration: none;
text-shadow: 0px -1px 1px #bdb5b4, 1px 1px 1px white;
position: absolute;
width: 3rem; }
.btnNew:hover {
background-image: linear-gradient(top, #fff, #f4f1ee);
color: #0088cc; }
.btnNew:active {
background-image: linear-gradient(top, #efedec, #f7f4f4);
box-shadow: 0 3px 5px 0 rgba(0, 0, 0, 0.4), inset opx -3px 1px 1px rgba(204, 198, 197, 0.5);
outline: none; }
.btnNew:active:after {
color: #dbd2d2;
text-shadow: 0px -1px 1px #bdb5b4, 0px 1px 1px white;
outline: none; }
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Flash</title>
<!-- Custom CSS -->
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div class="container">
<section class="input">
<div class="input_title">
<label class="input_title-label" for="title">Enter a Title</label>
<input class="input_title-input" id="title" type="text" placeholder="List of Towels">
</div>
<div class="input_question">
<label class="input_question-label" for="question">Enter a Question</label>
<input class="input_question-input" id="question" type="text" placeholder="What is 42?">
</div>
<div class="input_answer">
<label class="input_answer-label" for="answer">Enter an Answer</label>
<input class="input_answer-input" id="answer" type="text" placeholder="The Meaning Life, Universe, and Everything">
</div>
<div class="input_submit flex">
<button class="input_submit-button btnNew">Submit</button>
</div>
<div class="input_display"></div>
<div class="input_start flex">
<button type="button" class="input_start-btn btnNew" disabled>Start Quiz</button>
</div>
</section>
<section class="card">
<div class="card_container">
<div class="front">
<div class="inner">
<p class="quiz_question">Question</p>
</div>
</div>
<div class="back">
<div class="inner">
<p class="quiz_answer">Answer</p>
</div>
</div>
<div class="card_container-guess">
<input type="text" class="guess_input">
<button class="submitGuess btnNew">Submit Guess</button>
<button class="nextQuestion btnNew">Next Question</button>
</div>
</div>
</section>
</div>
<!-- Custom JS -->
<script src="js/scripts.js"></script>
</body>
</html>
I am wanting to figure out how to delete an item from the list
How about we change the last line of the function createDisplayItem to ..
function createDisplayItem(){
...
return newUl.appendChild(trashCan) // Added return
}
Now, you have an instance of the newly created trash can element being returned to the calling code, so now all we have to do is add a click event to this specific trash can element and let it delete its parent ul ..
submit.addEventListener("click", function() {
...
let trashCan = createDisplayItem();
trashCan.addEventListener('click', function(){
confirm('Are you sure you want to delete this?')
&& this.parentNode.remove()
})
...
});
So, since now in this code, each trash can takes care of its own parent element, you do not have to worry about finding the index from the parent display element anymore.

Categories