I wasn't sure how to write that question logically, I pretty much figured the togglw out, but I struggle with something else. When I click on one element and open it, I want to click on another one to open and the previously opened to close. It doesn't work, however. Whenever I click on another element, the opened one just closes without opening the other. Basically, I want to close the element only when I click on that specific element. Or when I click on another one (which kinda works) but in this case also want the other to open, if that makes sense. I am stuck at this point.
Thanks for any help.
Here is my codepen: https://codepen.io/danosvk/pen/JjLEGMK
Here is my code:
const questions = document.querySelectorAll("section");
const answers = document.querySelectorAll(".answer");
toggle = false
function open() {
for (let i = 0; i < answers.length; i ) {
answers[i].style.display = "none";
}
toggle = !toggle
this.lastElementChild.style.display = toggle ? "block" : "none"
}
questions.forEach((question) => question.addEventListener("click", open));
.card {
width: 20.4375rem;
background-color: #ffffff;
border-radius: 1.4375rem;
margin: auto;
padding: 132px 24px 48px;
text-align: center;
transform: translateY(-125px);
}
section {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #e8e8ea;
flex-wrap: wrap;
}
p {
color: var(--main-text-color);
font-size: 0.75rem;
}
.answer {
flex-basis: 100%;
text-align: left;
display: none;
}
<div >
<h1 >faq</h1>
<section>
<p >How many team members can i invite?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
You can invite up to 2 additional users on the Free plan. There is no
limit on team members for the Premium plan.
</p>
</section>
<section>
<p >What is the maximum file upload size?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
No more than 2GB. All files in your account must fit your allotted
storage space.
</p>
</section>
<section>
<p >How do I reset my password?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Click “Forgot password” from the login page or “Change password” from
your profile page. A reset link will be emailed to you.
</p>
</section>
<section>
<p >Can I cancel my subscription?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Yes! Send us a message and we’ll process your request no questions
asked.
</p>
</section>
<section>
<p >Do you provide additional support?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Chat and email support is available 24/7. Phone lines are open during
normal business hours.
</p>
</section>
CodePudding user response:
Using toggle
won't work as it is always false
when an answer is showing.
Instead, save the style of the clicked option before wiping all the answers, and then use it to determine whether or not to show the answer.
If this.lastElementChild.style.display
is ''
(i.e. on the first time the menu is clicked), it is set to none
.
const questions = document.querySelectorAll("section");
const answers = document.querySelectorAll(".answer");
function open() {
currentDisplay=this.lastElementChild.style.display||'none';
for (let i = 0; i < answers.length; i ) {
answers[i].style.display = "none";
}
if (currentDisplay=='none') this.lastElementChild.style.display = "block"
}
questions.forEach((question) => question.addEventListener("click", open));
.card {
width: 20.4375rem;
background-color: #ffffff;
border-radius: 1.4375rem;
margin: auto;
padding: 132px 24px 48px;
text-align: center;
transform: translateY(-125px);
}
section {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #e8e8ea;
flex-wrap: wrap;
}
p {
color: var(--main-text-color);
font-size: 0.75rem;
}
.answer {
flex-basis: 100%;
text-align: left;
display: none;
}
<div >
<h1 >faq</h1>
<section>
<p >How many team members can i invite?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
You can invite up to 2 additional users on the Free plan. There is no
limit on team members for the Premium plan.
</p>
</section>
<section>
<p >What is the maximum file upload size?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
No more than 2GB. All files in your account must fit your allotted
storage space.
</p>
</section>
<section>
<p >How do I reset my password?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Click “Forgot password” from the login page or “Change password” from
your profile page. A reset link will be emailed to you.
</p>
</section>
<section>
<p >Can I cancel my subscription?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Yes! Send us a message and we’ll process your request no questions
asked.
</p>
</section>
<section>
<p >Do you provide additional support?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Chat and email support is available 24/7. Phone lines are open during
normal business hours.
</p>
</section>
CodePudding user response:
I would do this by using this CSS rule to show the answers rather than changing their style inline:
.expanded .answer {
display: block;
}
...and then using event delegation on the .card
element that contains the FAQ to catch clicks anywhere within it; if the click passed through a section
, do this:
- If the
section
has theexpanded
class, remove it to un-expand the answer. - If the
section
doesn't have theexpanded
class, remove it from any other section that has it, then add it to thesection
that was clicked.
Here's the JavaScript part:
const card = document.querySelector(".card");
card.addEventListener("click", (event) => {
const section = event.target.closest("section");
if (section) {
if (section.classList.contains("expanded")) {
// This is the expanded one, un-expand it
section.classList.remove("expanded");
} else {
// This isn't the expanded one, un-expand the expanded
// one (if any) and expand this one
document.querySelector("section.expanded")?.classList.remove("expanded");
section.classList.add("expanded");
}
}
});
Notice the optional chaining on the querySelector
looking for an expanded section; it's there in case there is no expanded section yet.
Live Example:
const card = document.querySelector(".card");
card.addEventListener("click", (event) => {
const section = event.target.closest("section");
if (section) {
if (section.classList.contains("expanded")) {
// This is the expanded one, un-expand it
section.classList.remove("expanded");
} else {
// This isn't the expanded one, un-expand the expanded
// one (if any) and expand this one
document.querySelector("section.expanded")?.classList.remove("expanded");
section.classList.add("expanded");
}
}
});
.card {
width: 20.4375rem;
background-color: #ffffff;
border-radius: 1.4375rem;
margin: auto;
padding: 132px 24px 48px;
text-align: center;
transform: translateY(-125px);
}
section {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #e8e8ea;
flex-wrap: wrap;
}
p {
color: var(--main-text-color);
font-size: 0.75rem;
}
.answer {
flex-basis: 100%;
text-align: left;
display: none;
}
.expanded .answer {
display: block;
}
<div >
<h1 >faq</h1>
<section>
<p >How many team members can i invite?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
You can invite up to 2 additional users on the Free plan. There is no limit on team
members for the Premium plan.
</p>
</section>
<section>
<p >What is the maximum file upload size?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
No more than 2GB. All files in your account must fit your allotted storage space.
</p>
</section>
<section>
<p >How do I reset my password?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Click “Forgot password” from the login page or “Change password” from your profile page.
A reset link will be emailed to you.
</p>
</section>
<section>
<p >Can I cancel my subscription?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Yes! Send us a message and we’ll process your request no questions asked.
</p>
</section>
<section>
<p >Do you provide additional support?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Chat and email support is available 24/7. Phone lines are open during normal business
hours.
</p>
</section>
</div>
It might be worth adding a class to the section
and using that in the selectors, in case you have other parts of the page using section
, like this:
const card = document.querySelector(".card");
card.addEventListener("click", (event) => {
const section = event.target.closest(".faq");
if (section) {
if (section.classList.contains("expanded")) {
// This is the expanded one, un-expand it
section.classList.remove("expanded");
} else {
// This isn't the expanded one, un-expand the expanded
// one (if any) and expand this one
document.querySelector(".faq.expanded")?.classList.remove("expanded");
section.classList.add("expanded");
}
}
});
.card {
width: 20.4375rem;
background-color: #ffffff;
border-radius: 1.4375rem;
margin: auto;
padding: 132px 24px 48px;
text-align: center;
transform: translateY(-125px);
}
section {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #e8e8ea;
flex-wrap: wrap;
}
p {
color: var(--main-text-color);
font-size: 0.75rem;
}
.answer {
flex-basis: 100%;
text-align: left;
display: none;
}
.expanded .answer {
display: block;
}
<div >
<h1 >faq</h1>
<section >
<p >How many team members can i invite?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
You can invite up to 2 additional users on the Free plan. There is no limit on team
members for the Premium plan.
</p>
</section>
<section >
<p >What is the maximum file upload size?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
No more than 2GB. All files in your account must fit your allotted storage space.
</p>
</section>
<section >
<p >How do I reset my password?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Click “Forgot password” from the login page or “Change password” from your profile page.
A reset link will be emailed to you.
</p>
</section>
<section >
<p >Can I cancel my subscription?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Yes! Send us a message and we’ll process your request no questions asked.
</p>
</section>
<section >
<p >Do you provide additional support?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Chat and email support is available 24/7. Phone lines are open during normal business
hours.
</p>
</section>
</div>
CodePudding user response:
You can also fix it by simply keeping a reference (currentlyOpen
) of the currently opened section and using it in your event listener.
It would only require you to change some js and keep the same css.
Here's a little bit of code to explaining the change:
let currentlyOpen; // Keep track of the currently openend section.
function toggle() {
if (currentlyOpen) {
// Something currently open
currentlyOpen.lastElementChild.style.display = "none" // Close it
}
if (currentlyOpen === this) {
// The element the user clicked on is already opened, close it!
currentlyOpen.lastElementChild.style.display = "none" // Close it
currentlyOpen = undefined; // Delete it's refrence
return // And return (stop execution)
}
// Show clicked element
this.lastElementChild.style.display = "block"
// Store it for later
currentlyOpen = this
}
For more info see the code snipped:
const questions = document.querySelectorAll("section");
const answers = document.querySelectorAll(".answer");
let currentlyOpen;
function toggle() {
if (currentlyOpen) {
// Something currently open
currentlyOpen.lastElementChild.style.display = "none" // Close it
}
if (currentlyOpen === this) {
// Element is already open
currentlyOpen.lastElementChild.style.display = "none" // Hide it
currentlyOpen = undefined; // Delete it's refrence
return // And return
}
// Show clicked element
this.lastElementChild.style.display = "block"
// Store it for later
currentlyOpen = this
}
questions.forEach((question) => question.addEventListener("click", toggle));
.card {
width: 20.4375rem;
background-color: #ffffff;
border-radius: 1.4375rem;
margin: auto;
padding: 132px 24px 48px;
text-align: center;
transform: translateY(-125px);
}
section {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #e8e8ea;
flex-wrap: wrap;
}
p {
color: var(--main-text-color);
font-size: 0.75rem;
}
.answer {
flex-basis: 100%;
text-align: left;
display: none;
}
<div >
<h1 >faq</h1>
<section>
<p >How many team members can i invite?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
You can invite up to 2 additional users on the Free plan. There is no
limit on team members for the Premium plan.
</p>
</section>
<section>
<p >What is the maximum file upload size?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
No more than 2GB. All files in your account must fit your allotted
storage space.
</p>
</section>
<section>
<p >How do I reset my password?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Click “Forgot password” from the login page or “Change password” from
your profile page. A reset link will be emailed to you.
</p>
</section>
<section>
<p >Can I cancel my subscription?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Yes! Send us a message and we’ll process your request no questions
asked.
</p>
</section>
<section>
<p >Do you provide additional support?</p>
<img src="./images/icon-arrow-down.svg" alt="" />
<p >
Chat and email support is available 24/7. Phone lines are open during
normal business hours.
</p>
</section>
</div>
Or a working version hosted on jsfiddle: https://jsfiddle.net/fmr9tvw8/