Home > OS >  How to show and hide text on click of a button using JS event listener
How to show and hide text on click of a button using JS event listener

Time:10-17

const faqData = [
  {
    id: 1,
    question: "Who are we?",
    answer:
      "We enable upscaling careers through flexible, interactive and collaborative learning. We believe in building learning communities by bringing together mentors, young minds, and creators.",
  }
];

let accordianBody = document.querySelector('h1');
function createFaq() {
  // creating & adding all the FAQ's

  let firstQuery = document.createElement('h3');
  firstQuery.textContent = faqData[0].question;
  accordianBody.appendChild(firstQuery).className = "faq";

  // creating " " sign to the FAQ header
  let plusOne = document.createElement('span');

  // adding plus sign to the FAQ header
  plusOne.textContent = " ";
  firstQuery.appendChild(plusOne).className = "show_btn";

  // Adding addEventListener & displaying the answers.

  plusOne.addEventListener('click', answerFirst);
  function answerFirst() {
    let ans1 = document.createElement('p');
    ans1.textContent = faqData[0].answer;
    plusOne.appendChild(ans1);
  }
}

createFaq();
.faq {
  width: 100%;
  background-color: #4caf50;
  border-radius: 8px;
  margin: 0em 0em 1.4em;
  padding: 0.7em 1.4em;
}


.faq .show_btn {
  width: 24px;
  height: 24px;
  background-color: black;
  outline: none;
  box-shadow: none;
  border: none;
  color: white;
  margin: 0em;
  border-radius: 120px;
  cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Accordion</title>
    <link rel="stylesheet" href="index.css" />
  </head>
  <body>
    <div >
      <h1>MY FAQ's</h1>
    </div>
    
    <script id="faq-js" src="faq.js"></script>
  </body>
</html>

I am new to Javascript development so please excuse me for the beginner-level question. I want to show some text on the click of the button and hide it on the next click and keep toggling it as many times a user clicks it without changing my HTML.

Below is my code. I have achieved how to show the text but on the next click instead of hiding it the text is keep on adding.

const faqData = [
  {
    id: 1,
    question: "Who are we?",
    answer:
      "We enable upscaling careers through flexible, interactive and collaborative learning. We believe in building learning communities by bringing together mentors, young minds, and creators.",
  }
];

let accordianBody = document.querySelector('h1');
function createFaq() {
  // creating & adding all the FAQ's

  let firstQuery = document.createElement('h3');
  firstQuery.textContent = faqData[0].question;
  accordianBody.appendChild(firstQuery).className = "faq";

  // creating " " sign to the FAQ header
  let plusOne = document.createElement('span');

  // adding plus sign to the FAQ header
  plusOne.textContent = " ";
  firstQuery.appendChild(plusOne).className = "show_btn";

  // Adding addEventListener & displaying the answers.

  plusOne.addEventListener('click', answerFirst);
  function answerFirst() {
    let ans1 = document.createElement('p');
    ans1.textContent = faqData[0].answer;
    plusOne.appendChild(ans1);
  }
}

createFaq();



const faqData = [
  {
    id: 1,
    question: "Who are we?",
    answer:
      "We enable upscaling careers through flexible, interactive and collaborative learning. We believe in building learning communities by bringing together mentors, young minds, and creators.",
  }
];

let accordianBody = document.querySelector('h1');
function createFaq() {
  // creating & adding all the FAQ's

  let firstQuery = document.createElement('h3');
  firstQuery.textContent = faqData[0].question;
  accordianBody.appendChild(firstQuery).className = "faq";

  // creating " " sign to the FAQ header
  let plusOne = document.createElement('span');

  // adding plus sign to the FAQ header
  plusOne.textContent = " ";
  firstQuery.appendChild(plusOne).className = "show_btn";

  // Adding addEventListener & displaying the answers.

  plusOne.addEventListener('click', answerFirst);
  function answerFirst() {
    let ans1 = document.createElement('p');
    ans1.textContent = faqData[0].answer;
    plusOne.appendChild(ans1);
  }
}

createFaq();
.faq {
  width: 100%;
  background-color: #4caf50;
  border-radius: 8px;
  margin: 0em 0em 1.4em;
  padding: 0.7em 1.4em;
}

.faq .show_btn {
  width: 24px;
  height: 24px;
  background-color: black;
  outline: none;
  box-shadow: none;
  border: none;
  color: white;
  margin: 0em;
  border-radius: 120px;
  cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Accordion</title>
    <link rel="stylesheet" href="index.css" />
  </head>
  <body>
    <div >
      <h1>MY FAQ's</h1>
    </div>
    
    <script id="faq-js" src="faq.js"></script>
  </body>
</html>

And below is my small HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Accordion</title>
    <link rel="stylesheet" href="index.css" />
  </head>
  <body>
    <div >
      <h1>MY FAQ's</h1>
    </div>
    
    <script id="faq-js" src="faq.js"></script>
  </body>
</html>

Please help me out and thanks in advance.

CodePudding user response:

I think you can add extra data of boolean type to event listener which changes on each click that will solve your issue.

Like

    onClick(if(b is true)
{let x = hide;
    then b = false;
return;
}
 else if(b is false){
    let x = show;
 then b =true;
return;
}

this way toggeling will be ensured.

BTW I'm to new to JS but it works for me.

CodePudding user response:

What you did wrong?

  • you added the answer in a span instead of next after to the question. (create problem when you want to change the content of hide show button to -)
  • You added the answer to the DOM (HTML) by dynamically.
  • you had put your question and answer in <h1> tag.
  • you added your firstAnswer() function in the createFaq() function.
  • In faqData[] there is no need for an id in each question because the index of array can be used as their ids.

What's the logic?

The accordion adds the question and answer to the DOM (HTML) at same time not when user click to show the answer. The difference is only that the answers are hidden by adding style display: none to the <p> element as default. And when user clicked on button to show the answer the class active with styling display: block is added to the element <p>. That's all about accordion.

I had just fixed "adding more answers instead of hiding it on a click". I don't recommend you use this code. But this one is for your understanding. So, this snippet had same logic for only one question.

const faqData = [{
  id: 1,
  question: "Who are we?",
  answer: "We enable upscaling careers through flexible, interactive and collaborative learning. We believe in building learning communities by bringing together mentors, young minds, and creators."
}];

let accordianBody = document.querySelector('h1');

function createFaq() {
  // creating & adding all the FAQ's

  let firstQuery = document.createElement('h3');
  firstQuery.textContent = faqData[0].question;
  accordianBody.appendChild(firstQuery).className = "faq";

  // creating " " sign to the FAQ header
  let plusOne = document.createElement('span');

  // adding plus sign to the FAQ header
  plusOne.textContent = " ";
  firstQuery.appendChild(plusOne).className = "show_btn";



  // Adding addEventListener & displaying the answers.

  //plusOne.addEventListener('click', answerFirst);

  //function answerFirst() {
  let ans1 = document.createElement('p');
  ans1.textContent = faqData[0].answer;
  plusOne.appendChild(ans1);
  //}
}

createFaq();

const showHideBtn = document.querySelector(".show_btn");

showHideBtn.addEventListener('click', showHideAnswer);

function showHideAnswer() {
const question = document.querySelector(".faq span.show_btn p");
  question.classList.toggle("active");
}
.faq {
  width: 100%;
  background-color: #4caf50;
  border-radius: 8px;
  margin: 0em 0em 1.4em;
  padding: 0.7em 1.4em;
}

.faq .show_btn {
  width: 24px;
  height: 24px;
  background-color: black;
  outline: none;
  box-shadow: none;
  border: none;
  color: white;
  margin: 0em;
  border-radius: 120px;
  cursor: pointer;
}

.show_btn p{
  display: none;
}

.show_btn .active {
  display: block;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Accordion</title>
  <link rel="stylesheet" href="index.css" />
</head>

<body>
  <div >
    <h1>MY FAQ's</h1>
  </div>

  <script id="faq-js" src="faq.js"></script>
</body>

</html>

For multiple FAQ

I rearranged the code by renaming the variables and fixing wrong append of the elements such as answer to the <span> tag. I recommend you use this code not above because it have almost all issues discussed above. In this code you just have to add questions and answers to the faqData[]

const faqData = [
    {
        question: "Who are we?",
        answer: "We enable upscaling careers through flexible, interactive and collaborative learning. We believe in building learning communities by bringing together mentors, young minds, and creators."
    },
    {
        question: "Lorem Ipsum?",
        answer: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed elementum malesuada tortor, in pharetra nisl gravida at."
    }
]

// We are not adding question and answer into this heading any more.
let accordianBody = document.querySelector('h1');

function createFaq(question, answer) {
    // Edited - Renaming firstQuery to faqQuestion, ans1 to faqAnswer, plusOne to showHideBtn
    // Edited - Now appending faqQuestion, and faqAnswer to faqContainer

    let faqContainer = document.createElement('div');
    faqContainer.className = "faq-container"


    // creating & adding all the FAQ's

    let faqQuestion = document.createElement('h3');
    faqQuestion.textContent = question;
    faqContainer.appendChild(faqQuestion).className = "faq";

    // creating " " sign to the FAQ header
    let showHideBtn = document.createElement('span');

    // adding plus sign to the FAQ header
    showHideBtn.textContent = " ";
    faqQuestion.appendChild(showHideBtn).className = "show_btn";



    // Adding addEventListener & displaying the answers.

    //plusOne.addEventListener('click', answerFirst);

    //function answerFirst() {
    let faqAnswer = document.createElement('p');
    faqAnswer.textContent = answer;
    faqContainer.appendChild(faqAnswer);

    //}
    // Edited - append faq question next after to the heading not inside it
    let accordionBody = document.querySelector(".accordian_body");
    accordionBody.appendChild(faqContainer);

}

for (let i = 0; i < faqData.length; i  ) {
    // Passing values to the function to display the FAQs
    createFaq(faqData[i].question, faqData[i].answer)
}
// This one can also be done with forEach or for-of loop like that
// for (const iterator of faqData) {
//     createFaq(faqData[i].question, faqData[i].answer)
// }



const showHideBtn = document.querySelectorAll(".faq-container .show_btn");
// This will ahow and hide the specific answer;
for (let i = 0; i < showHideBtn.length; i  ) {
    const btn = showHideBtn[i];
    // You can also a seprate function like another but there is only two lines of code we want for this function
    btn.addEventListener("click", function () {
        let answer = document.querySelectorAll(".faq-container p");

        // This will add/remove the class to hide/show the answer
        answer[i].classList.toggle("active");

        // This one is for changing the content of hide show button
        if (answer[i].classList.contains("active")) {
            btn.textContent = "-";
        }
        else {
            btn.textContent = " ";
        }
    });
};
.faq-container {
  width: 100%;
  background-color: #4caf50;
  border-radius: 8px;
  margin: 0em 0em 1.4em;
  padding: 0.7em 1.4em;
}

.faq-container .show_btn {
  padding: 5px 10px;

  width: 24px;
  height: 24px;
  background-color: black;
  outline: none;
  box-shadow: none;
  border: none;
  color: white;
  margin: 0em;
  border-radius: 120px;
  cursor: pointer;
}

.faq-container p {
  display: none;
}

.faq-container .active {
  display: block;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Accordion</title>
  <link rel="stylesheet" href="index.css" />
</head>

<body>
  <div >
    <h1>MY FAQ's</h1>
  </div>

  <script id="faq-js" src="faq.js"></script>
</body>

</html>

  • Related