Remove instance of inner element only when specific parent is clicked - javascript

I have a series of elements where I'd like it when one of the boxes is clicked the inner box on that specific element disappears. I've been playing around with it but can't get it work. I'm wondering if I should be using this in the code?
In the example below I want it so when you click one of the red boxes, that particular box's inner yellow box disappears, but only the yellow box inside the red box that is clicked.
I need to do it with without adding any more classes or IDs to the HTML.
CodePen: https://codepen.io/emilychews/pen/dyNPwEx
var boxOuter = document.querySelectorAll(".box-outer"),
boxInner = document.querySelectorAll(".box-inner");
if (boxOuter) {
boxOuter.forEach(function (item) {
item.addEventListener("click", function () {
// code goes here
});
});
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 120vh;
}
.box-outer {
position: relative;
width: 10rem;
height: 5rem;
background: red;
margin: 1rem;
cursor: pointer;
}
.box-inner {
width: 1rem;
height: 1rem;
background: yellow;
position: absolute;
bottom: 0.5rem;
right: 0.5rem;
}
<main class="main-wrapper">
<div class="box-outer">
<div class="box-inner"></div>
</div>
<div class="box-outer">
<div class="box-inner"></div>
</div>
<div class="box-outer">
<div class="box-inner"></div>
</div>
</main>

This should do the job
var boxOuter = document.querySelectorAll(".box-outer"),
boxInner = document.querySelectorAll(".box-inner");
if (boxOuter) {
boxOuter.forEach(function (item) {
item.addEventListener("click", function () {
//This will delete everything inside the box... Clear all child nodes
this.innerHTML = '';
//Hide inner child
//this.children[0].style.visibility = 'hidden';
// code goes here
});
});
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 120vh;
}
.box-outer {
position: relative;
width: 10rem;
height: 5rem;
background: red;
margin: 1rem;
cursor: pointer;
}
.box-inner {
width: 1rem;
height: 1rem;
background: yellow;
position: absolute;
bottom: 0.5rem;
right: 0.5rem;
}
<main class="main-wrapper">
<div class="box-outer">
<div class="box-inner"></div>
</div>
<div class="box-outer">
<div class="box-inner"></div>
</div>
<div class="box-outer">
<div class="box-inner"></div>
</div>
</main>

Instead of selecting the inner element globally, you could make this inside the listener. And then use the setAttribute method to change the display property to 'none'.
var boxOuter = document.querySelectorAll(".box-outer");
if (boxOuter) {
boxOuter.forEach(function (item) {
item.addEventListener("click", function () {
const boxInner = item.querySelector(".box-inner"); // captures the respective box
boxInner.setAttribute("style", "display: none;"); // sets the display attribute
});
});
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 120vh;
}
.box-outer {
position: relative;
width: 10rem;
height: 5rem;
background: red;
margin: 1rem;
cursor: pointer;
}
.box-inner {
width: 1rem;
height: 1rem;
background: yellow;
position: absolute;
bottom: 0.5rem;
right: 0.5rem;
}
<main class="main-wrapper">
<div class="box-outer">
<div class="box-inner"></div>
</div>
<div class="box-outer">
<div class="box-inner"></div>
</div>
<div class="box-outer">
<div class="box-inner"></div>
</div>
</main>

Related

Can't get transition to work for accordion menu

I'm having a problem where I want to have an accordion menu that automatically expands to fit content that is dynamically added. I want the accordion body to expand its height to accommodate more comments as they are added. The accordion works, but it will not take a transition.
Can somebody assist me with what I am doing wrong? Thanks.
const accordionItemHeader = document.querySelector(".accordionItemHeader");
accordionItemHeader.addEventListener("click", event => {
accordionItemHeader.classList.toggle("active");
const accordionItemBody = document.querySelector(".accordionItemBody");
if (accordionItemHeader.classList.contains("active")) {
accordionItemBody.style.setProperty("max-height", "100%");
} else {
accordionItemBody.style.setProperty("max-height", "0");
}
})
.accordionItemHeader {
padding: 0 10px;
cursor: pointer;
position: relative;
background-color: $spruce;
display: flex;
align-items: center;
h5 {
color: $iceBlue;
}
}
.accordionItemHeader::after, .accordionItemHeader.active::after {
font-size: 3.5rem;
position: absolute;
right: 0;
top: 0;
display: flex;
justify-content: flex-end;
align-items: center;
height: 100%;
padding: 0 10px;
color: $iceBlue;
}
.accordionItemHeader::after {
content: "\25BC";
}
.accordionItemHeader.active::after {
content: "\25B2";
}
.accordionContent {
padding: 10px;
}
.accordionItemBody {
max-height: 0;
overflow: hidden;
border: 1px $spruce solid;
padding: 0;
// transition: max-height 0.5s; <-- this is what won't work
}
<div class="accordion">
<div class="accordionItem">
<div class="accordionItemHeader">
<h5>Comments</h5>
</div>
<div class="accordionItemBody">
<div class="accordionContent">
<ul class="commentsPosted">
<!--dynamic comments posted go here-->
<li class="placeholderComment">
<p>No comments yet</p>
</li>
</ul>
</div><!--accordionContent div end -->
</div> <!--accordionitembody div end-->
</div><!--accordionItem div end-->
</div><!--accordion div end-->

disable left or right arrow at the last item

Just made a simple div slider with navigation arrows. The div slider works just fine, except, I want some sort of CSS styling to be applied to the arrows.
That is, when a user clicks the left or right arrow, up to the last item, apply CSS styling telling the user they've reached the end of the slider.
let buttonLeft = document.getElementById('slide_left')
let buttonRight = document.getElementById('slide_right')
let container = document.getElementById('slider')
buttonLeft.addEventListener('click', function() {
container.scrollLeft -= 90
})
buttonRight.addEventListener('click', function() {
container.scrollLeft += 90
})
body {
background-color: #555;
height: 100vh;
display: grid;
align-items: center;
justify-items: center;
font-family: 'Helvetica';
}
div#slide_wrapper {
width: 440px;
display: flex;
justify-content: space-between;
height: fit-content;
}
div#slider {
width: 350px;
display: flex;
height: fit-content;
flex-wrap: nowrap;
overflow: hidden;
}
div.thumbnail {
min-width: 80px;
min-height: 80px;
cursor: pointer;
display: grid;
place-items: center;
font-size: 30px;
}
div.thumbnail:not(:last-child) {
margin-right: 10px;
}
div.thumbnail:nth-child(1) {
background-color: darkturquoise;
}
div.thumbnail:nth-child(2) {
background-color: goldenrod;
}
div.thumbnail:nth-child(3) {
background-color: rebeccapurple;
}
div.thumbnail:nth-child(4) {
background-color: powderblue;
}
div.thumbnail:nth-child(5) {
background-color: firebrick;
}
div.thumbnail:nth-child(6) {
background-color: sienna;
}
div.thumbnail:nth-child(7) {
background-color: bisque;
}
div.thumbnail:nth-child(8) {
background-color: navy;
}
div#slide_wrapper>button {
height: fit-content;
align-self: center;
font-size: 24px;
font-weight: 800;
border: none;
outline: none;
}
div#slide_wrapper>button:hover {
cursor: pointer;
}
<div id="slide_wrapper">
<button id="slide_left" class="slide_arrow">❮</button>
<div id="slider">
<div class="thumbnail active">1</div>
<div class="thumbnail">2</div>
<div class="thumbnail">3</div>
<div class="thumbnail">4</div>
<div class="thumbnail">5</div>
<div class="thumbnail">6</div>
<div class="thumbnail">7</div>
<div class="thumbnail">8</div>
</div>
<button id="slide_right" class="slide_arrow">❯</button>
</div>
Simply check to see if you need to disable each button based on the position of the scroll. Then if there is a need to disable a button, add the disabled class to the button, otherwise remove it.
Future enhancements.
Remove the hardcoded 360 value for the scroll end. This should be calculated from the size of the carousel items and the width of the viewport.
Allow more than one carousel to work with the same code. This could be achieved by using a javascript class that would hold the elements inside an object, separate from other carousels.
See the demo:
let buttonLeft = document.getElementById('slide_left')
let buttonRight = document.getElementById('slide_right')
let container = document.getElementById('slider')
let checkScroll = function() {
if (container.scrollLeft <= 0)
buttonLeft.classList.add("disabled");
else
buttonLeft.classList.remove("disabled");
if (container.scrollLeft >= 360)
buttonRight.classList.add("disabled");
else
buttonRight.classList.remove("disabled");
}
checkScroll();
buttonLeft.addEventListener('click', function() {
container.scrollLeft -= 90;
checkScroll();
})
buttonRight.addEventListener('click', function() {
container.scrollLeft += 90;
checkScroll();
})
body {
background-color: #555;
height: 100vh;
display: grid;
align-items: center;
justify-items: center;
font-family: 'Helvetica';
}
div#slide_wrapper {
width: 440px;
display: flex;
justify-content: space-between;
height: fit-content;
}
div#slider {
width: 350px;
display: flex;
height: fit-content;
flex-wrap: nowrap;
overflow: hidden;
}
div.thumbnail {
min-width: 80px;
min-height: 80px;
cursor: pointer;
display: grid;
place-items: center;
font-size: 30px;
}
div.thumbnail:not(:last-child) {
margin-right: 10px;
}
div.thumbnail:nth-child(1) {
background-color: darkturquoise;
}
div.thumbnail:nth-child(2) {
background-color: goldenrod;
}
div.thumbnail:nth-child(3) {
background-color: rebeccapurple;
}
div.thumbnail:nth-child(4) {
background-color: powderblue;
}
div.thumbnail:nth-child(5) {
background-color: firebrick;
}
div.thumbnail:nth-child(6) {
background-color: sienna;
}
div.thumbnail:nth-child(7) {
background-color: bisque;
}
div.thumbnail:nth-child(8) {
background-color: navy;
}
div#slide_wrapper>button {
height: fit-content;
align-self: center;
font-size: 24px;
font-weight: 800;
border: none;
outline: none;
}
div#slide_wrapper>button:hover {
cursor: pointer;
}
.slide_arrow.disabled {
opacity: 0.2;
cursor: auto !important;
}
<div id="slide_wrapper">
<button id="slide_left" class="slide_arrow">❮</button>
<div id="slider">
<div class="thumbnail active">1</div>
<div class="thumbnail">2</div>
<div class="thumbnail">3</div>
<div class="thumbnail">4</div>
<div class="thumbnail">5</div>
<div class="thumbnail">6</div>
<div class="thumbnail">7</div>
<div class="thumbnail">8</div>
</div>
<button id="slide_right" class="slide_arrow">❯</button>
</div>
a simple solution to this is to actually create a css class that defines the style of arrows when there are no more items and then just add/remove class based on current index of items

Positioning an absolute element above other elements

So I am building this frontendmentor site and im having trouble positioning the shopping cart div on top of the rest of the elements. At first i tried using z-index but apparently that doesnt work with elements that have a position style. I used position relative on the parent and absolute on the child so it would always appear under the shopping cart icon. Is there any other way to force an element on top or should i change the way i position the div.
.right-container {
padding: 1rem;
}
.account-container {
display: flex;
align-items: center;
position: relative;
}
.cart-icon-container {
margin-right: 2rem;
}
.cart-icon-container img {
height: 30px;
width: 30px;
aspect-ratio: 1;
}
.shopping-cart-overlay {
position: absolute;
top: 5rem;
right: 100px;
width: 400px;
border-radius: 10px;
box-shadow: 0 1rem 10px rgba(0, 0, 0, 0.185);
}
.shopping-cart-content {
display: flex;
justify-content: center;
align-items: center;
padding: 2rem 1rem;
}
<div class="right-container">
<div class="account-container">
<div class="shopping-cart-overlay">
<div class="shopping-cart-header">
<h4>Cart</h4>
</div>
<div class="shopping-cart-content">
<p>Your cart is empty</p>
</div>
</div>
<a href="/index.html" class="cart-icon-container">
<img src="./images/icon-cart.svg" alt="cart">
</a>
<img class="avatar" src="./images/image-avatar.png" alt="profile-pic">
</div>
</div>
Well it does work. Read this to get a better understanding of how z-index works with position. You just couldn't notice it because the div was transparent.
Check out the snippet below. It's your exact code, but I changed the background and positioned the .shopping-cart-overlay element closer to the other elements, just to show you that it actually works.
.right-container {
padding: 1rem;
}
.account-container {
display: flex;
align-items: center;
position: relative;
}
.cart-icon-container {
margin-right: 2rem;
}
.cart-icon-container img {
height: 30px;
width: 30px;
aspect-ratio: 1;
}
.shopping-cart-overlay {
position: absolute;
//top: 5rem;
//right: 100px;
width: 400px;
border-radius: 10px;
box-shadow: 0 1rem 10px rgba(0, 0, 0, 0.185);
/* Changes */
top: 0;
left: 125px;
z-index: 99;
background-color: red;
}
.shopping-cart-content {
display: flex;
justify-content: center;
align-items: center;
padding: 2rem 1rem;
}
<div class="right-container">
<div class="account-container">
<div class="shopping-cart-overlay">
<div class="shopping-cart-header">
<h4>Cart</h4>
</div>
<div class="shopping-cart-content">
<p>Your cart is empty</p>
</div>
</div>
<a href="/index.html" class="cart-icon-container">
<img src="./images/icon-cart.svg" alt="cart">
</a>
<img class="avatar" src="./images/image-avatar.png" alt="profile-pic">
</div>
</div>

How can I stop my center div from changing position after I SlideUp another divs?

I'm creating simple page with a <header> and a <section>. In the section I have 3 divs and I am positioning them with display: flex; and justify-content: space-between.
The problem is that I also use JS slideToggle() on two of them (extreme ones). It is changing the layout of my center div after they are going up. How can I do it so that my center div doesn't change position after one of the others is slid up?
$(document).ready(function() {
$('#playlist').click(function() {
$('#nav').slideToggle();
});
});
$(document).ready(function() {
$('#songs').click(function() {
$('#listSongs').slideToggle();
});
});
section {
display: flex;
justify-content: space-between;
}
#listSongs {
margin-top: 50px;
height: 550px;
background-color: black;
border-radius: 5px;
font-size: 25px;
width: 200px;
}
#listSongs p {
margin-top: 5px;
width: 200px;
text-align: center;
overflow: hidden;
height: 35px;
line-height: 50px;
color: white;
}
#player {
color: red;
}
#nav {
margin-top: 50px;
height: 550px;
background-color: black;
border-radius: 20px;
width: 200px;
}
.hidden {
margin-top: 50px;
height: 550px;
background-color: black;
border-radius: 20px;
width: 200px;
visibility: hidden;
}
#nav p {
text-align: center;
}
#nav ul {
list-style-type: none;
text-align: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>
<div id="listSongs">
<p>Authors:</p>
<div class="after"></div>
</div>
<div id="player">
<p>something</p>
</div>
<div id="nav">
<p>something</p>
</div>
</section>
The issue is because when the slideUp/slideDown/slideToggle methods complete, they set display: none on the target element. This is what causes the layout of your page to shift.
To workaround, and improve the animation, you can use CSS instead. Use the transition property to animate the height setting. Then you can toggle a class which sets height: 0 on the target element. Try this:
$(document).ready(function() {
$('#playlist').click(function() {
$('#nav').toggleClass('hide');
});
$('#songs').click(function() {
$('#listSongs').toggleClass('hide');
});
});
body { background-color: #CCC; }
section {
display: flex;
justify-content: space-between;
}
section > div.panel {
margin-top: 50px;
height: 550px;
background-color: black;
border-radius: 5px;
font-size: 25px;
width: 200px;
transition: height 0.4s;
overflow: hidden;
}
section > div.panel.hide {
height: 0;
}
section > div.panel p {
margin-top: 5px;
width: 200px;
text-align: center;
overflow: hidden;
height: 35px;
line-height: 50px;
color: white;
}
#player {
color: red;
}
#nav {
border-radius: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="playlist">Playlist</button>
<button id="songs">Songs</button>
<section>
<div id="listSongs" class="panel">
<p>Authors:</p>
<p>lorem ipsum</p>
<div class="after"></div>
</div>
<div id="player">
<p>something</p>
</div>
<div id="nav" class="panel">
<p>something</p>
</div>
</section>
Note that I also rearranged some of the CSS to make it more generic with less repetition.

How to overlap images using flexbox while maintaing it's ability responsive design

click here to see my code
The goal here is to perfectly overlap the images.
The eyes (blue ovals) should display on the face (peach circle). I'm using chrome as my browser. But hope it will display the same on any browser used.
Like so (minus the nose):
What I tried:
changing the position of the images from relative to absolute (With one image set as absolute I should have been able to move it anywhere I wanted on the page.)
setting align-self: flex-start (Sometimes browsers have weird default setting. I was told this might override a chrome default that was stopping me from moving the image.)
setting align-self: center (This was also an attempt to override a chrome default)
I can't figure out how to overlap the two images let alone add any code to my CSS file that will move the images.
function setDefaultImage(){
var defaultImage = document.getElementById(img_face).src = "https://drive.google.com/file/d/1_seSuUcgJgd5qQTUcreDuYo_zfVpRzsa/view?usp=sharing";
}
.flex-container {
display: flex;
background-color: darkred;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
.flex-container > div {
background-color: black;
margin: 1%;
padding: 5%;
width:38%;
}
img{
align-self: flex-start;
text-align: center;
width: 100%;
}
.img_face{
position: absolute;
top: 0;
z-index: 1;
}
.img_eyes{
position: absolute;
top: 0;
z-index: 2;
}
<!DOCTYPE html>
<html>
<body>
<div class="flex-container">
<div id = "left">
<button type="reset" id="reset" class="button" onclick = setDefaultImage()>Reset</button>
</div>
<div id = "right">
<img id="img_face" src="white_face.png" alt="White Face" >
<img id="img_eyes" src="blue_eyes.png" alt="Blue Eyes" >
</div>
</div>
Here's a couple different approaches with room for tinkering to help your learning. Happy Holidays!
hiUser = (val) => {
const box1 = document.getElementById('box1'),
box2 = document.getElementById('box2'),
blah = `${val}px`;
box1.style.height = blah;
box1.style.width = blah;
box2.style.height = blah;
box2.style.width = blah;
}
div {
display: flex;
align-items: center;
/* default initial values */
height: 100px;
width: 100px;
margin-top: 2rem;
}
span {
background-color: blue;
height: 20%;
width: 10%;
border-radius: 50%;
margin-bottom: 30%;
}
figure, #box1 {
position: relative;
background-color: wheat;
border-radius: 50%;
margin: 0;
}
figure {
height: 100%;
width: 100%;
}
#box1 {
justify-content: space-around;
}
#box1 span {
margin-right: 20%;
}
#box1 span:first-child {
margin-left: 20%;
margin-right: 0;
}
figure:before, figure:after {
content: '';
display: block;
position: absolute;
top: 25%;
background-color: blue;
height: 20%;
width: 10%;
border-radius: 50%;
}
figure:before {
left: 30%;
}
figure:after {
right: 30%;
}
label {
display: block;
margin: 2rem 0 1rem 0;
}
Slide to change size:
<input type="range"
name="fu"
min="0"
max="500"
onchange="hiUser(this.value)"
oninput="hiUser(this.value)">
<label>Flex;</label>
<div id="box1">
<span></span>
<span></span>
</div>
<label>Pseudo;</label>
<div id="box2">
<figure></figure>
</div>

Categories

Resources