I created a sidebar toggle and also gave background opacity but when I click another area or when closed the sidebar the background opacity didn't close. when I click the button the dropdown-content show and the background-opacity show but when I click again on the button the dropdown content closed but the background opacity does not close. How I did it. Please help me. I gave the code below. If someone can help me it will be very helpful for me. I try so many times but in the end, I can't do it. 😥
function toggleDropDown(id) {
document.querySelectorAll('.dropdown-content').forEach(el => el.id === id ? el.classList.toggle('show') : el.classList.remove("show"));
document.body.style.backgroundColor = "rgba(0,0,0,0.4)";
}
document.addEventListener('click', (e) => {
// cases where we want to close the dropdown
if (e.target.closest(".dropdown") === null) {
document.querySelectorAll('.dropdown-content').forEach(el => el.classList.remove("show"));
}
});
*{margin:0;padding:0;}
.dropdown-content{
position: fixed;
width: 30%;
height:100%;
background-color: rgb(255,0,0);
margin-left: 20%;
top:0;
display:none;
z-index:100;
}
.dropbtn{width:20%}
.show{display:block;}
<div class="dropdown">
<button class="dropbtn" onclick="toggleDropDown('openContent')">open</button>
<div class="dropdown-content" id="openContent">Hello, Div</div>
</div>
<h1>Hello World, Heading 1</h1>
First, I would suggest to create a variable that keeps track of the current state of dropdown – which is either true or false.
Plus, I don’t see the benefit in using document.querySelectorAll and having to loop over every element, when you could just directly get the element by addressing its id (openContent)... unless you would want to reuse the function for other cases?
As you are also listening on a click event on the document, we have to watch out for event bubbling by calling e.stopPropagation. In the case of the button for example, this means that we only fire the event for the button but not for the document. Since the button is a child of the document, it would otherwise detect a click event for both and fire twice.
const dropdownContent = document.getElementById("openContent");
let dropDownVisible = false;
function toggleDropDown(e) {
// we need this to prevent the event bubbling from the dropdown button to the document
e.stopPropagation();
// set the dropDownVisible state to the opposite it has been before
dropDownVisible = !dropDownVisible;
if (dropDownVisible) {
dropdownContent.classList.add("show");
document.body.classList.add("bgcolor");
} else {
dropdownContent.classList.remove("show");
document.body.classList.remove("bgcolor");
}
}
// we need this to prevent the event bubbling from the dropdown to the document
dropdownContent.addEventListener("click", (e) => {
e.stopPropagation();
});
// listen for click events on the document
document.addEventListener("click", (e) => {
// -> if the dropdown is visible, toggle its state
dropDownVisible && toggleDropDown(e);
});
* {
margin: 0;
padding: 0;
}
.dropdown-content {
position: fixed;
width: 30%;
height: 100%;
background-color: rgb(255, 0, 0);
margin-left: 20%;
top: 0;
display: none;
z-index: 100;
}
.dropbtn {
width: 20%;
}
.show {
display: block;
}
.bgcolor {
background-color: rgba(0, 0, 0, 0.4);
}
<body>
<div class="dropdown">
<button class="dropbtn" onclick="toggleDropDown(event)">
open
</button>
<div class="dropdown-content" id="openContent">Hello, Div</div>
</div>
<h1>Hello World, Heading 1</h1>
</body>
You will have to remove also the "body" background.
document.body.style.backgroundColor = "initial";
function toggleDropDown(id) {
document.querySelectorAll('.dropdown-content').forEach(el => el.id === id ? el.classList.toggle('show') : el.classList.remove("show"));
document.body.style.backgroundColor = "rgba(0,0,0,0.4)";
}
document.addEventListener('click', (e) => {
// cases where we want to close the dropdown
if (e.target.closest(".dropdown") === null) {
document.querySelectorAll('.dropdown-content').forEach(el => el.classList.remove("show"));
document.body.style.backgroundColor = "initial";
}
});
*{margin:0;padding:0;}
.dropdown-content{
position: fixed;
width: 30%;
height:100%;
background-color: rgb(255,0,0);
margin-left: 20%;
top:0;
display:none;
z-index:100;
}
.dropbtn{width:20%}
.show{display:block;}
<div class="dropdown">
<button class="dropbtn" onclick="toggleDropDown('openContent')">open</button>
<div class="dropdown-content" id="openContent">Hello, Div</div>
</div>
<h1>Hello World, Heading 1</h1>
Add class to body document.body.classList.add('bgcolor'); and remove after close the dropdown
function toggleDropDown(id) {
document.querySelectorAll('.dropdown-content').forEach(el => el.id === id ? el.classList.toggle('show') : el.classList.remove("show"));
document.body.classList.add('bgcolor');
}
document.addEventListener('click', (e) => {
// cases where we want to close the dropdown
if (e.target.closest(".dropdown") === null) {
document.querySelectorAll('.dropdown-content').forEach(el => el.classList.remove("show"));
document.body.classList.remove('bgcolor');
}
});
*{margin:0;padding:0;}
.dropdown-content{
position: fixed;
width: 30%;
height:100%;
background-color: rgb(255,0,0);
margin-left: 20%;
top:0;
display:none;
z-index:100;
}
.dropbtn{width:20%}
.show{display:block;}
.bgcolor{
background-color:rgba(0,0,0,0.4);
}
<div class="dropdown">
<button class="dropbtn" onclick="toggleDropDown('openContent')">open</button>
<div class="dropdown-content" id="openContent">Hello, Div</div>
</div>
<h1>Hello World, Heading 1</h1>
Related
I have several identical divs and each of them contains a button that is hidden. I want to make button visible when you hover on the parent div. I wrote this code:
const cardElements = document.querySelectorAll('.middle_section__president_section');
const learnButtons = document.querySelectorAll('.president_section__button');
cardElements.forEach((cardElement) => {
cardElement.addEventListener('mouseover', () => {
learnButtons.forEach((learnButton) => {
learnButton.style.height = "50px";
learnButton.style.opacity = "1";
learnButton.style.border = "3px solid rgb(129, 129, 129)";
});
});
cardElement.addEventListener('mouseout', () => {
learnButtons.forEach((learnButton) => {
learnButton.style.height = "0px";
learnButton.style.opacity = "0";
learnButton.style.border = "0px solid rgb(129, 129, 129)";
});
});
})
carElements is parent, learnButtons - child.
but with this code when i hover on one div buttons appears in every similiar div. How can i make button appear only on hovered div?
Use the Event object
cardElement.addEventListener('mouseover', () => {
learnButtons.forEach((learnButton) => {
convert this to
cardElement.addEventListener('mouseover', (e) => {
var learnButton = e.target;
There's no need to use JS for this. As Mister Jojo/traktor pointed out in their comments you can use the CSS :hover pseudo-class instead.
The key CSS line is .box:hover button { visibility: visible;} which means "when you hover over the parent container make its button visible".
.box { width: 50%; display: flex; flex-direction: column; border: 1px solid lightgray; margin: 0.25em; padding: 0.25em;}
button { visibility: hidden; margin: 0.25em 0; border-radius: 5px; background-color: lightgreen; }
.box:hover button { visibility: visible;}
.box:hover, button:hover { cursor: pointer; }
<section class="box">
Some text
<button>Click for a surprise!</button>
</section>
<section class="box">
Some text
<button>Click for a surprise!</button>
</section>
<section class="box">
Some text
<button>Click for a surprise!</button>
</section>
It is bad practice to iterate over all elements and give each an event, as you can add 1 event handler to the parent and when the event happens you can check the affected element by the event parameter in the handler call back
parent.addEVentListener('mouseover', (e) => {
if(e.target.classList.contains('middle_section__president_section')) {
// Do
}
});
I have this div which shows/hides with display:none/block by clicking on an id #cart. The div opens and closes by clicking on element with the id but I want to close the div on body click too. How can I do it please?
Code I am using is below:
jQuery("#cart").on("click", function() {
jQuery(".shopping-cart").fadeToggle( "fast");
});
jQuery("#cart, body").on("click", function() {
jQuery(".shopping-cart").fadeToggle("fast");
});
What you can do is add a listener to the entire window and check for clicks. When there is a click, we check which element has been clicked and check on whether it's the element. We repeat this for the parent element as well.
<!DOCTYPE html>
<html>
<head>
<script>
function checkClickOutsiteElement(clickedElement, elementToCheck){
var iterator = clickedElement;
while(true){
// The click was in the element.
if( iterator === elementToCheck )
return;
// Go to the parent.
if( !iterator.parentElement ){
alert('outside menu');
return;
}
iterator = iterator.parentElement;
}
}
window.addEventListener('click', function(event){
checkClickOutsiteElement(event.target, document.getElementById('menu'));
});
</script>
</head>
<body>
<div class="wrapper">
<div id="menu" style="width: 100px; height: 100px; background-color: red;"></div>
</div>
<div class="wrapper">
<div id="not_menu" style="width: 100px; height: 100px; background-color: green;"></div>
</div>
</body>
</html>
You probably want two separate functions, since your cart button should toggle both ways, but the body click handler should only toggle out.
Protip: on() isn't doing anything for you that click() wouldn't, the way you're using it. The latter is a bit cleaner.
jQuery("#cart").click(function() {
jQuery(".shopping-cart").fadeToggle("fast");
});
jQuery("body").click(function() {
jQuery(".shopping-cart").fadeOut("fast");
});
Protip 2: Easily and safely alias jQuery to $ like so:
jQuery(function($) { // document ready with dollar alias
$("#cart").click(function() {
...
});
I have this div which shows/hides with display:none/block by clicking
on an id #cart. The div opens and closes by clicking on element with
the id but I want to close the div on body click too.
In vanilla javascript, you can:
write a function to show / hide the div
add a click event listener to #cart
add a click event listener to body
Working Example:
// Grab #cart
const cart = document.getElementById('cart');
// Grab .myDiv
const myDiv = document.getElementsByClassName('div')[0];
// Function to toggle .myDiv
const toggleMyDiv = (e) => {
if (e.target === e.currentTarget) {
myDiv.dataset.display = (myDiv.dataset.display === 'show') ? 'hide' : 'show';
}
}
// Add Click Event Listener to #cart
cart.addEventListener('click', toggleMyDiv, false);
document.body.addEventListener('click', toggleMyDiv, false);
body,
#cart {
cursor: pointer;
}
div {
display: inline-block;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
font-weight: bold;
}
#cart {
color: rgb(255, 255, 255);
background-color: rgb(255, 0, 0);
}
.div {
color: rgb(255, 0, 0);
background-color: rgb(255, 255, 0);
}
.div[data-display="show"] {
opacity: 1;
}
.div[data-display="hide"] {
opacity: 0;
}
<div id="cart">Cart</div>
<div class="div show" data-display="show">myDiv</div>
I have two divs, top and bottom. Both divs have dynamic height, the top div will show or hide depending on a variable.
I would like to add in a sliding animation to the top div when showing or hiding, but the bottom div should stick with the top div and slide with it too.
var hide = true;
var trigger = document.getElementById("trigger");
var topdiv = document.getElementById("topdiv");
trigger.addEventListener('click', function() {
if (hide) {
topdiv.classList.add('hide');
} else {
topdiv.classList.remove('hide');
}
hide = !hide;
});
div {
position: relative;
display: block;
width: 100%;
padding: 10px;
}
.top {
background: #999;
}
.body {
background: #555;
}
.hide {
display: none !important;
}
<div id="topdiv" class="top hide">
<p>Top</p>
</div>
<div class="body">
<p>Body</p>
<button id="trigger">
Trigger
</button>
</div>
I tried adding transform animations, but the effect is only applied to the top div while the bottom div remains unanimated.
#keyframes topDivAnimate {
from {
transform: translateY(-100%);
}
to {
transform:translateY(0%);
}
}
Help is much appreciated.
I would use CSS transition rather than animation. I've found it easiest to do by animating the lower div rather than the upper one, and changing its position so that it covers the top one (or, of course, not). See demonstration below, I've made as minimal changes as I could to the CSS and JS:
var cover = true;
var trigger = document.getElementById("trigger");
var bottomdiv = document.getElementsByClassName("body")[0];
trigger.addEventListener('click', function() {
if (cover) {
bottomdiv.classList.add('cover');
} else {
bottomdiv.classList.remove('cover');
}
cover = !cover;
});
div {
position: relative;
display: block;
width: 100%;
padding: 10px;
}
.top {
background: #999;
}
.body {
background: #555;
transform: translateY(0%);
transition: transform 0.5s;
}
.cover {
transform: translateY(-100%);
}
<div id="topdiv" class="top hide">
<p>Top</p>
</div>
<div class="body">
<p>Body</p>
<button id="trigger">
Trigger
</button>
</div>
Are you looking something like this? Then please try this:
var trigger = document.getElementById("trigger");
var topdiv = document.getElementById("topdiv");
trigger.addEventListener('click', function() {
if ($('#topdiv').css('display') == 'none') {
$(topdiv).slideDown();
} else {
$(topdiv).slideUp();
}
});
div {
position: relative;
display: block;
width: 100%;
padding: 10px;
}
.top {
display: none;
background: #999;
}
.body {
background: #555;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="topdiv" class="top hide">
<p>Top</p>
</div>
<div class="body">
<p>Body</p>
<button id="trigger">
Trigger
</button>
</div>
Try this code and see if that's the effect you wanted. It uses the Animate.css library so you'll need to link that in your <head></head>
function animateCSS(element, animationName, callback) {
const node = document.querySelector(element)
node.classList.add('animated', animationName)
function handleAnimationEnd() {
node.classList.remove('animated', animationName)
node.removeEventListener('animationend', handleAnimationEnd)
if (typeof callback === 'function') callback()
}
node.addEventListener('animationend', handleAnimationEnd)
}
var hide = false;
var trigger = document.getElementById("trigger");
var topdiv = document.getElementById("topdiv");
trigger.addEventListener('click', function() {
if (!hide) {
topdiv.classList.remove('hide');
animateCSS('.body', 'slideInDown');
animateCSS('#topdiv', 'slideInDown');
} else {
animateCSS('#topdiv', 'slideOutUp', function() {
topdiv.classList.add('hide');
})
animateCSS('.body', 'slideOutUp');
}
hide = !hide;
});
Working Codepen demo of my solution
Here's some more explanation on how to use the Animate.css library.
I have 2 divs that are initially hidden
<div id="whistle" style="display:none;">
<div id="lean" style="display:none;">
I also have a div that is visible
<div id="me" style="display:block">
I have jQuery code that allows only the #whistle or #lean divs to be open at once, their buttons will hide the other.
I currently have code that also hides the #me div, but I would now like the #me div to open back up when both #whistle and #lean are closed.
If you want to see the site, the link is maxdev.tk
The jQuery code is
$(document).ready(function(){
$("#calc").click(function(){
$("#whistle").hide(600);
$("#lean").toggle(900);
});
});
$(document).ready(function(){
$("#whi").click(function(){
$("#lean").hide(600);
$("#whistle").toggle(900);
});
});
This is one way to solve it. Find it also as a pen at the end of this post.
$(document).ready(function() {
function callback() {
if( $('#whistle').hasClass('hidden') && $('#lean').hasClass('hidden') ) {
$('#me').removeClass('hidden');
} else {
$('#me').addClass('hidden');
}
}
$('button[data-for=whistle]').on('click', function() {
$('#whistle').toggleClass('hidden');
$('#lean').addClass('hidden');
callback();
});
$('button[data-for=lean]').on('click', function() {
$('#lean').toggleClass('hidden');
$('#whistle').addClass('hidden');
callback();
});
})
.hidden {
opacity: 0;
height: 0;
overflow: hidden;
padding: 0;
}
div {
background-color: #ccc;
border-radius: 25px;
margin-top: 20px;
padding: 50px;
text-align: center;
transition-duration: 0.4s;
width: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button data-for="whistle">Whistle</button>
<button data-for="lean">Lean</button>
<div id="whistle" class="hidden">Whistle!</div>
<div id="lean" class="hidden">Lean!</div>
<div id="me">Me!</div>
http://codepen.io/anon/pen/yNJrwe
Add this code to the end of whatever buttons' click function.
if( !$('#whistle').is(':visible') && !$('#lean').is(':visible') ) {
$('#me').css("display","block"); // or use .show();
} else {
$('#me').css("display","none"); // or use .hide();
}
I have tow toggles. I want appear only one toggle at the time. When i click to second toggle then first toggle should be close.
Javascript
$('#bar').click(function () {
$('#foo').slideToggle('slow');
});
$('#bar1').click(function () {
$('#foo1').slideToggle('slow');
});
HTML
<button id="bar">bar</button>
<div id="foo"></div>
<button id="bar1">bar1</button>
<div id="foo1"></div>
CSS
#foo {
width: 100px;
height: 100px;
background-color: green;
display:none;
}
#foo1 {
width: 100px;
height: 100px;
background-color: green;
display:none;
}
jsfiddle
You can use classes instead of id's
$('.bar').click(function () {
$('.foo').hide(); // hide previous elements
$(this).next().show('slow'); // show next element in the DOM (it will be <div> with class 'foo')
});
Example
I did what you want with classes,
the accordion style,
$('#bar, #bar1').click(function () {
var id = '#'+$(this).attr('data-for');
if ($(id).hasClass('open')) {
$(id).toggleClass('open');
}
else if ($('#foo').hasClass('open') || $('#foo1').hasClass('open')) {
$('#foo').toggleClass('open');
$('#foo1').toggleClass('open');
}
else {
$(id).toggleClass('open');
}
});
#foo {
width: 100px;
height: 0;
background-color: green;
display:block;
transition: all .5s;
}
#foo1 {
width: 100px;
height: 0;
background-color: green;
display:block;
transition: all .5s;
}
#foo.open, #foo1.open {
height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="bar" data-for="foo">bar</button>
<div id="foo"></div>
<button id="bar1" data-for="foo1">bar1</button>
<div id="foo1"></div>
hi i have two ways which you can achive it
in this case the first div is sliding up when second div is opening
$('#bar').click(function () {
$("div").slideUp("slow");
$('#foo').slideToggle('slow');
});
$('#bar1').click(function () {
$("div").slideUp("slow");
$('#foo1').slideToggle('slow');
});
case 1 in fiddler
in second case am hiding the first div when am opening the second div
$('#bar').click(function () {
$("div").hide();
$('#foo').slideToggle('slow');
});
$('#bar1').click(function () {
$("div").hide();
$('#foo1').slideToggle('slow');
});
case 2 in fiddler
i hope my answer helps you :)