Accordion FAQ populated from Google Sheet

Hi. I made a little accordion FAQ that pulls the text from a google spreadsheet with the help of @MarkHunte script. However all the panels are open by default, and I need to have them all closed at the start and only open the one that is clicked on (closing the previously opened if there is an open instance). Secondly I have only been able to make this work by initiating the javascript onMouseClick, of the Accordion container, but it only seems to work on doubleclick to open/close the panels. Any help to make this a little smoother would be greatly appreciated. I’m testing Google Sheets as a kind of content management solution.

Thank you.GoogleSheetAccordion.zip (101.7 KB)

This pulls the spreadsheet data:

function GetSheet(hypeDocument, element, event){  		
	$.getJSON("https://spreadsheets.google.com/feeds/list/1qSJs6inNb8oCt-yP-mHLqqGZrLLwWRfyDsbkBH2bT4s/od6/public/values?alt=json", function(data) { 
   
  var Accordion = document.getElementById('accordion');
  
  var items = [];

  for (i = 0; i < data.feed.entry.length; i++) {    
  var Question = data.feed.entry[i].gsx$question.$t
  var Answer = data.feed.entry[i].gsx$answer.$t

   items.push( '<button class="accordion">' + Question + '</button><div class="panel"><p>' + Answer + '</p></div>');
  
   Accordion.innerHTML = '<div>' + items + '</div>';
} 
});

This does the Accordion part

 function Accordion(hypeDocument, element, event){  
var acc = document.getElementsByClassName("accordion");
var i;

for (i = 0; i < acc.length; i++) {
  acc[i].addEventListener("click", function() {
    /* Toggle between adding and removing the "active" class,
    to highlight the button that controls the panel */
    this.classList.toggle("active");

    /* Toggle between hiding and showing the active panel */
    var panel = this.nextElementSibling;
    if (panel.style.display === "block") {
      panel.style.display = "none";
    } else {
      panel.style.display = "block";
    }
  });
} 
}

This does the CSS part

	<style>
 		/* Style the buttons that are used to open and close the accordion panel */
.accordion {
  background-color: #eee;
  color: #444;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  text-align: left;
  border: none;
  outline: none;
  transition: 0.4s;
}

/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
.active, .accordion:hover {
  background-color: #ccc;
}

/* Style the accordion panel. Note: hidden by default */
.panel {
  padding: 0 18px;
  background-color: white;
  display: none;
  overflow: hidden;
}
	</style>

The issue with the answers showing up ahead of time is that a CSS rule from Hype is overriding the head html css. You can fix this by unchecking Protect from external styles in the Document Inspector.

For the double-click issue, the problem is that the Accordion() function only should be run once, and after the sheet has been fetched and HTML setup. So to fix this you’ll want to first remove the On Mouse Click handler that runs that code. Then you can plop a manual call towards the end of the GetSheet() code just after the DOM has been setup in the getJSON callback. Basically below this line:

   Accordion.innerHTML = '<div>' + items + '</div>';

Add:

   hypeDocument.functions()["Accordion"]();

And then I think it will work as expected.

1 Like

Thank you Jonathan! All working as expected… except the toggle. I think I’m getting closer as I can now toggle the state of the headers. But it doesn’t toggle the collapsing of the panel elements? Trying various combinations of removing classes, instead of styling visibility (block/none)? But not much luck. Updated file: GoogleSheetAccordion.zip (100.4 KB)

var acc = document.getElementsByClassName('accordion')

for (var i = 0; i < acc.length; i++) {
  var elem = acc[i];
  
  elem.addEventListener('click', function() {
    for (var j = 0; j < acc.length; j++)
       
    acc[j].classList.remove("active");
   
 this.classList.add('active');
  var thispanel = this.nextElementSibling;

  thispanel.classList.toggle('vis');
           
  });
 }
1 Like

Searched and found a simple JS on the web. Works really well! The only thing left is to get rid of the pesky commas that separate the lines. (any ideas anyone?)

For anyone interested, here is the final file with a neat working accordion powered by Google Sheets. :grinning:

GoogleSheetAccordion.zip (100.4 KB)

var acc = document.getElementsByClassName("accordion");
var i;

for (i = 0; i < acc.length; i++) {
  acc[i].onclick = function() {
    var active = document.querySelector(".accordion.active");
    if (active && active != this) {
      active.classList.remove("active");
      active.nextElementSibling.classList.remove("show");
    }
    this.classList.toggle("active");
    this.nextElementSibling.classList.toggle("show");
  }
}
2 Likes

to avoid the commas in the output :

Accordion.innerHTML = items.join('');

and you should move the above line and setting of innerHTML after the iteration …

3 Likes

Thank you @h_classen that did the trick!