Faulty toggle functionality within a JavaScript-created accordion panel

HTML

I'm looking to add a FAQ question within the div with the class "section-center"


<body>

    <section class="questions">
        <div class="title">
            <h2>FAQ SECTION</h2>
        </div>
        <div class="section-center">
<!-- dynamic data insert here -->
        </div>
    </section>
    <!-- script -->
    <script src="/script.js"></script>
</body>

</html>

CSS

With the use of JavaScript, we will be able to add or remove the "show-text" class. When the "show-text" class is added, the 'question-text' class will display block (making the answer visible), the 'minus-icon' class will display inline (revealing the minus icon which was initially hidden), and the 'plus-icon' class will have display none (the plus icon disappears).

.question-text {
    display: none;
}

.show-text .question-text {
    display: block;
}

.minus-icon {
    display: none;
}

.show-text .minus-icon {
    display: inline;
}

.show-text .plus-icon {
    display: none;
}

JS

This array holds questions and answers

const faq = [
  {
    ques: 'this is test question',
    answer: 'this is test answer ',
  },
  {
    ques: 'this is test question',
    answer: 'this is test answer ',
  },
]

We are traversing the DOM in order to insert the question/answer where needed.

const sectionCenter = document.querySelector('.section-center');

The function displayQuestion is called when the webpage loads to show the question and answer.

window.addEventListener('DOMContentLoaded', () => {
  displayQuestions(faq);
});

const questions = document.querySelectorAll('.question');

//console.log(questions);

This portion of code enables the feature of automatically closing an open question when another question is opened by clicking on a toggle button.

questions.forEach((question) => {
  const btn = question.querySelector('.question-btn');

  btn.addEventListener('click', () => {
    questions.forEach((curQuestion) => {
      if (curQuestion !== question) {
        curQuestion.classList.remove('show-text');
      }
    });
    question.classList.toggle('show-text');
  });
});

A function to display question and answer

// function to display questions

function displayQuestions(items) {
  let display = items.map(({ ques, answer }) => {
    return ` 
            <article class="question">
                <div class="question-title">
                    <P>${ques}</P>
                    <button type="button" class="question-btn">
                        <span class="plus-icon">
                            <i class="far fa-plus-square"></i>
                        </span>

                        <span class="minus-icon">
                            <i class="far fa-minus-square"></i>
                        </span>
                    </button>
                </div> 
                
                 <div class="question-text">
                    <p>${answer}</p>
                </div>
            </article>
          `;
  });
  display = display.join('');
  //   console.log(display);
  sectionCenter.innerHTML = display;
}

Answer №1

After restructuring the code, I created a function named addEventListenersToQuestions to handle adding event listeners to the question buttons. This function is now called after displayQuestions runs within the DOMContentLoaded event listener callback function.

The main reason for this change was that even though the code for adding event listeners came after the displayQuestions code in source order, it was actually executing before displayQuestions had completed its process. In JavaScript, event listener callbacks are only executed after the current section of code has finished execution.

const faq = [
  {
    ques: 'this is test question 1',
    answer: 'this is test answer 1',
  },
  {
    ques: 'this is test question 2',
    answer: 'this is test answer 2',
  },
];

const sectionCenter = document.querySelector('.section-center');

window.addEventListener('DOMContentLoaded', () => {
  displayQuestions(faq);
  addEventListenersToQuestions();
});


function addEventListenersToQuestions() {
  const questions = document.querySelectorAll('.question');

  questions.forEach((question) => {
    const btn = question.querySelector('.question-btn');

    btn.addEventListener('click', () => {
      questions.forEach((curQuestion) => {
        if (curQuestion !== question) {
          curQuestion.classList.remove('show-text');
        }
      });
      question.classList.toggle('show-text');
    });
  });
}

// function to display questions

function displayQuestions(items) {
  let display = items.map(({ ques, answer }) => {
    return ` 
            <article class="question">
                <div class="question-title">
                    <P>${ques}</P>
                    <button type="button" class="question-btn">
                        <span class="plus-icon">
                            +
                        </span>

                        <span class="minus-icon">
                            -
                        </span>
                    </button>
                </div> 
                
                 <div class="question-text">
                    <p>${answer}</p>
                </div>
            </article>
          `;
  });
  display = display.join('');
  //   console.log(display);
  sectionCenter.innerHTML = display;
}
.question-text {
    display: none;
}

.show-text .question-text {
    display: block;
}

.minus-icon {
    display: none;
}

.show-text .minus-icon {
    display: inline;
}

.show-text .plus-icon {
    display: none;
}
<section class="questions">
    <div class="title">
        <h2>FAQ SECTION</h2>
    </div>
    <div class="section-center">
<!-- dynamic data insert here -->
    </div>
</section>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using async/await with Middleware in Express

I'm struggling to grasp the concept of writing middleware in Express that uses async/await without leaving a floating Promise after execution. Despite reading numerous blogs and StackOverflow posts, it appears that there is a common pattern for utiliz ...

Modify the animation on Material UI Autocomplete with an underline effect

In my project, I am utilizing a Material UI Autocomplete component for the "Faculdade" field. Nonetheless, I have observed that the animation/transition effect when this component is focused involves spreading from the middle outwards. I desire the animati ...

Difficulty with the increment of my counter when using addeventlistener

I'm currently facing a challenge that I can't seem to figure out... Here is the issue (in JavaScript): export default { name: "TodoList", data() { return { title: "", content: null, isDone: true, count: 0, n ...

What is the best way to locate an element in the HTML content that contains the class 'sponsored-post'?

This code snippet is flawed as it assigns 'none' to the variable article, even though the variable articles contains all the listing results. articles = soup.select('.listingResult') for article in articles: # <div class=&qu ...

Struggling with a character entity in Javascript? Learn how to escape it and avoid any display issues (such as showing

document.title = ("welcome &rarr; farewell"); Trying to display the arrow symbol "→" but it's not showing correctly. Any tips on how to properly escape it? ...

What is the best way to hide or eliminate spinners/arrows in react-select?

I am currently utilizing react-select for my project, but I'm encountering an issue with removing the spinners/arrows from the dropdown menu. So far, I have successfully removed the default separator "|" and Dropdown Indicator using the following cod ...

Sharing parameters between functions in JavaScript

I have a working code but I want to modify the function getLocation to accept 2 arguments that will be passed to getDistanceFromLatLonInKm within the ajmo function. Currently, getDistanceFromLatLonInKm has hardcoded arguments and I would like to use variab ...

Battle of Kingdoms API ajax

When attempting to access Clash of Clans API information in this script, the following error is encountered: Refused to execute script from 'https://api.clashofclans.com/v1/leagues?authorization=Bearer%20eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiIsImtpZCI6Ij ...

Mapping URLs to objects in JavaScript, TypeScript, and Angular4

I have implemented a class called SearchFilter class SearchFilter { constructor(bucket: string, pin: number, qty: number, category: string) { } } When the user performs a search, I populate the filter i ...

VueJS - Vuefire - Unexpected Error: document.onSnapshot is not a valid function

I'm currently working on integrating Vuefire into my project. I have been following the instructions provided on the Vuefire website, but I am encountering an error. db.js: import firebase from 'firebase/app' import 'firebase/firestore ...

Why does my computed property become undefined during unit testing of a head() method in Vue.js with Nuxt.js?

In my Vue.js + Nuxt.js component, I have implemented a head() method: <script> export default { name: 'my-page', head() { return { title: `${this.currentPage}` }; }, ... } </script> ...

Tips for binding to a single input box within an ngFor loop

Can anyone lend a hand with some code? I'm working on a straightforward table using ngFor, but I'm facing an issue with input binding. The problem is that all the input fields generated by ngFor display the same value when typing. How can I preve ...

Maintain modifications in AngularJS modal even after closure

I have an HTML file with some AngularJS code for a modal window. <div ng-controller="ModalDemoCtrl"> <script type="text/ng-template" id="myModalContent.html"> <div class="modal-header"> <h3>I'm a modal!</h3> ...

What is the proper way to implement parameters and dependency injection within a service?

My objective is to achieve the following: (function(){angular.module('app').factory("loadDataForStep",ls); ls.$inject = ['$scope','stepIndex'] function ls ($scope, stepIndex) { if ($routeParams ...

Display full desktop version on mobile devices with minimized view and no need for horizontal scrolling

While it may seem unusual, my client has requested temporarily removing responsiveness from the site to view the desktop version on mobile. I initially tried removing the responsive meta tag, but encountered horizontal scrolls on the page. My goal is to di ...

What is the most effective way to transmit a conditional operator via a TypeScript boolean field?

Currently, as part of my transition to typescript, I am working on incorporating a conditional operator into the table component provided by Ant Design. const paginationLogic = props.data.length <= 10 ? false : true return ( <> ...

following the history.back() function call, the subsequent codes are executed

<?php $ok_register = 0; if($ok_register != 1) { ?> <javascript type="text/javascript"> alert("1"); history.back(); </javascript> <?php } ?> <javascript type="text/javas ...

The callback function does not get invoked when using JSONP

Learning jsonP has been a challenge for me as I am relatively new to it. I have done my research by reading various articles but when trying out a simple example, the callback function fails to execute. Surprisingly, there are no errors or exceptions logge ...

Display div content depending on the clicked ID in AngularJS

Unique Header Links HTML <ul ng-controller="pageRouteCtrl"> <li ui-sref-active="active"> <a ui-sref="home" class="" ng-click="getPageId('live-view')">LIVE</a> </li> <li> <a ng-clic ...

Unexpected behavior encountered with Angular module dependency injection

Having some difficulty managing dependencies for my node app. Here's the current structure: app.js var app = angular.module('myApp', ['myController', 'myFactory', 'rzModule', 'chart.js', 'myServ ...