HTML:
<!-- hero -->
<div class="hero">
<div class="banner">
<h1>Modal</h1>
<button class="btn modal-btn">open modal</button>
</div>
</div>
<!-- end of hero -->
<!-- modal -->
<div class="modal-overlay">
<div class="modal-container">
<h4>
Some lorem
</h4>
<button class="close-btn">
<i class="fas fa-times"></i>
</button>
</div>
<!-- end of modal -->
CSS:
.modal-overlay {
/*Some css codes to modify overlay*/
visibility: hidden;
z-index: -10;
}
.open-modal {
visibility: visible;
z-index: 10;
}
JS:
const btnModal = document.querySelector('.modal-btn');
const overlayModal = document.querySelector('.modal-overlay');
const btnCloseModal = document.querySelector('.close-btn');
function openModal(){
overlayModal.classList.add('open-modal')
}
function closeModal(){
overlayModal.classList.remove('open-modal')
}
btnModal.addEventListener('click',openModal)
btnCloseModal.addEventListener('click', closeModal)
Is it the most efficient way for modals?
How .open-modal overwrites .modal-overlay's properties? Sometimes it worked for me, sometimes not. What do I need to give attention?
Yes, it is. People usually use display: block and display: none. But visibilty also okay.
Your class aren't removed. You can try to use, if this resolve your problem
element.style.display = 'block' //
Here some references https://gomakethings.com/two-ways-to-set-an-elements-css-with-vanilla-javascript/
Related
I'm working with Vue 3 and Bootstrap 5.
I have a button and two inputs. When I click the button I want to have a "milky" overlay like following:
How can I achieve this?
Code to work with:
<template>
<div class="row">
<button class="btn btn-dark" #click="overlayMilky()">Button</button>
</div>
<div class="row mt-2">
<div class="col-12">
<span>Input 2</span>
<input class="form-control" />
</div>
<div class="col-12">
<span>Input 3</span>
<input class="form-control" />
</div>
</div>
</template>
<script>
export default {
methods: {
overlayMilky() {
//set overlay to milky
}
}
}
</script>
First, you need to surround the inputs with a container element and give this element position: relative and add to it a child which will be the overlay, this should have position: absolute to be absolute to the container element, also should have width: 100%; height: 100%; top: 0px; left: 0px; to take the full size of the container element and then conditionally with v-if you can show/hide it with a state
<div v-if="showOverlay" class="overlay"></div>
methods: {
overlayMilky() {
this.showOverlay = !this.showOverlay;
//set overlay to milky
},
},
This is a full example of code.
<template>
<div>
<div class="row">
<button class="btn btn-dark" #click="overlayMilky()">Button</button>
</div>
<div class="container">
<div v-if="showOverlay" class="overlay"></div>
<div class="row mt-2">
<div class="col-12">
<span>Input 2</span>
<input class="form-control" />
</div>
<div class="col-12">
<span>Input 3</span>
<input class="form-control" />
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
showOverlay: false,
};
},
methods: {
overlayMilky() {
this.showOverlay = !this.showOverlay;
//set overlay to milky
},
},
};
</script>
<style>
.container {
position: relative;
}
.overlay {
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
background-color: rgba(255, 255, 255, 0.4);
}
</style>
You need to add a data field that will describe the "milky" overlay state.
So all you need to do in the overlayMilky method is to set this.milkyOverlay = true.
Then use this milkyOverlay property to add the milky css class or show milky div on top.
Can anyone advice me why the allTabs forEach wont work when I am trying to add the .none class
?
When clicking second item the other class should disappear but it doesn't,
let allTabs = document.querySelectorAll('.none');
function setActiveTab(tab) {
allTabs.forEach((tabs) => {
tabs.classList.add("none")
})
let singleTab = document.querySelector(`.${tab}`)
singleTab.classList.toggle("block")
}
.none {
display: none;
}
.block {
display: block;
}
<div>
<button onclick="setActiveTab('first')">
Test1
</button>
<button onclick="setActiveTab('second')">
Test2
</button>
</div>
<div class="none first">
first tab
</div>
<div class="none second">
second tab
</div>
A better approach is just to remove the none class on the current tab. You won't need the block class.
let allTabs = document.querySelectorAll('.none');
function setActiveTab(tab) {
allTabs.forEach((tabs) => {
tabs.classList.add("none")
})
let singleTab = document.querySelector(`.${tab}`)
singleTab.classList.remove("none")
}
.none {
display: none;
}
<div>
<button onclick="setActiveTab('first')">
Test1
</button>
<button onclick="setActiveTab('second')">
Test2
</button>
</div>
<div class="none first">
first tab
</div>
<div class="none second">
second tab
</div>
if you look at the inspector, the class none is always present.
Im pretty new to Web Development, so I am sorry for this stupid question.
I have 4 Divs with different classes.
Icon-feature1 - 4 and each of them has a different active class.
I want that my JS is removing all actives and adding active on the targeted (clicked) div.
The class "master-feature" I added to have all of the Divs something in common and be able to be selected. It's maybe not the best way, but I came up with this and thought it's okay.
let swapactive = document.getElementsByClassName('master-feature');
for (let i = 0; i < swapactive.length; i++) {
swapactive[i].addEventListener('click', activateClass);
}
function activateClass(e) {
for (let i = 0; i < swapactive.length; i++) {
swapactive[i].classList.remove('active');
}
e.target.classList.add('active');
}
.icon-feature1 {
margin-right: 10px;
margin-top: 20px;
float: left;
content: url("/static/img/feature1_blue.svg");
animation: pulsate 3s ease-out infinite;
}
.icon-feature1.active {
content: url("/static/img/feature1.svg");
animation-play-state: paused;
}
<div class="row">
<div class="col-sm-6 pb-10">
<div class="active icon-feature1 master-feature">
</div>
<div class="p-3 pt-3 col-content-box col-features-active col-features-not-active col-round-border col-feature">
<p id="fs-16">
<b id="fs-18">Feature 1</b><br/> Feature 1 Description
</p>
</div>
<div class="row">
<div class="col-sm-12">
<div class="icon-feature2 master-feature">
</div>
<div class="p-3 pt-3 col-content-box col-features-not-active col-round-border col-feature">
<p id="fs-16">
<b id="fs-18">Feature 2</b><br/> Feature 2 Description
</p>
</div>
</div>
<div class="col-sm-12">
<div class="icon-feature3 master-feature">
</div>
<div class="p-3 pt-3 col-content-box col-features-not-active col-round-border col-feature">
<p id="fs-16">
<b id="fs-18">Feature 3</b><br/> Feature 3 Description
</p>
</div>
</div>
<div class="col-sm-12">
<div class="icon-feature4 master-feature">
</div>
<div class="p-3 pt-3 col-content-box col-features-not-active col-round-border col-feature">
<p id="fs-16">
<b id="fs-18">Feature 4</b><br/> Feature 4 Description
</p>
</div>
</div>
</div>
</div>
</div>
If I click a div, nothing is happening. What did I made wrong?
Any ideas?
Thank you in advance.
Use e.currentTarget instead of e.target and your code works.
I have attached 2 of my divs below. When the icon inside heart is clicked, if the class name is far then it should change from far to fas. But if the class name has been changed to fas, it should change back to far. I'm not sure how to do this becuase I have many divs.
<div class="cont">
<h2>A header</h2>
<div class="heart">
<i onclick="like(example)" class="fas fa-heart"></i>
</div>
</div>
<div class="cont">
<h2>A header#2</h2>
<div class="heart">
<i onclick="like1()" class="fas fa-heart"></i>
</div>
</div>
This is the javascript I currently have.
function like(example){
if(example.classList=="far fa-heart"){
example.classList.toggle="fas fa-heart";
} else{
example.classList.toggle="far fa-heart";
}
}
I want this to be in just 1 function without making a variable for all the tags in javascript. I'm still learning... Thanks for your help!
I can't find a good dupetarget for this. Basically, you can hook click on a parent element containing all of these (body if nothing else) and only take action if the click passed through the fa-heart element when bubbling:
theContainer.addEventListener("click", function(event) {
// Did the click pass through an `.fa-heart` element?
const heart = event.target.closest(".fa-heart");
if (heart && this.contains(heart)) {
// Yes, and that element is inside this container; toggle it
heart.classList.toggle("far");
heart.classList.toggle("fas");
}
});
See closest, contains, and toggle for details.
Live Example:
const theContainer = document.body;
theContainer.addEventListener("click", function(event) {
// Did the click pass through an `.fa-heart` element?
const heart = event.target.closest(".fa-heart");
if (heart && this.contains(heart)) {
// Yes, and that element is inside this container; toggle it
heart.classList.toggle("far");
heart.classList.toggle("fas");
}
});
.fa-heart {
display: inline-block;
width: 20px;
color: white;
}
.fas {
background-color: red;
}
.fas::after {
content: 'fas';
}
.far {
background-color: green;
}
.far::after {
content: 'far';
}
<div class="cont">
<h2>A header</h2>
<div class="heart">
<i class="fas fa-heart"></i>
</div>
</div>
<div class="cont">
<h2>A header#2</h2>
<div class="heart">
<i class="fas fa-heart"></i>
</div>
</div>
Edited the answer to add the HTML and import fontawesome, since my first answer was done on my phone.
function toggleHearts() {
document.querySelectorAll(".heart")
.forEach(elm => elm.addEventListener("click", (e) => {
e.target.classList.toggle("far");
e.target.classList.toggle("fas");
}));
}
toggleHearts()
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/css/all.min.css" integrity="sha512-YWzhKL2whUzgiheMoBFwW8CKV4qpHQAEuvilg9FAn5VJUDwKZZxkJNuGM4XkWuk94WCrrwslk8yWNGmY1EduTA==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>
<div class="container">
<h2>A header</h2>
<div class="heart">
<i class="fas fa-heart"></i>
</div>
</div>
<div class="container">
<h2>A header#2</h2>
<div class="heart">
<i class="fas fa-heart"></i>
</div>
</div>
You can use a function that accepts an HTML element as a parameter and toggles the classes.
function like1(element) {
element.classList.toggle("fas");
element.classList.toggle("far");
}
.fas {
color: green;
}
.far {
color: red;
}
<div class="cont">
<h2>A header</h2>
<div class="heart">
<i onclick="like1(this)" class="fas fa-heart">Like</i>
</div>
</div>
<div class="cont">
<h2>A header#2</h2>
<div class="heart">
<i onclick="like1(this)" class="fas fa-heart">Like</i>
</div>
</div>
I'm trying to create a function that reveals additional content by clicking a button.
I've got a script that displays the content by default - How do I switch it so the content is hidden by default and only displays when the button is clicked?
function revealContent() {
var x = document.getElementById("additionalContent");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
<div class="col-10 text-center">
<button class="btn btn-sm btn-primary" onclick="revealContent()">Show More Options...</button>
</div>
<div class="col-10" id="additionalContent">
<p>Content!</p>
</div>
You just have to have the style display: none applied by default and then toggle it. classList.toggle is a good use for this. You can do something like:
.hidden {
display: none;
}
<div class="col-10 text-center">
<button class="btn btn-sm btn-primary" onclick="revealContent()">Show More Options...</button>
</div>
<div class="col-10 hidden" id="additionalContent">
<p>Content!</p>
</div>
<script>
function revealContent() {
var x = document.getElementById("additionalContent");
x.classList.toggle('hidden');
}
</script>
<div class="col-10" id="additionalContent" style="display:none">
<p>Content!</p>
</div>
EDIT: You've to add the style="display:none" to make this as default when the page is loaded.