Solved

Why is my FAQ accordion functionality only partially working?

andylewie
Excursionist
20 0 2

Hello,

 

I am trying to make my FAQ page easier for users by adding the accordion functionality as per this page:
https://github.com/mirceapiturca/Sections/tree/master/FAQ

 

For some reason only the top section expands/collapses while the lower sections don't.

 

Can anyone help me please?

 

This is the page:
https://www.humdinger.nz/pages/faqs

 

Cheers, Andrew

Accepted Solution (1)
Mircea_Piturca
Shopify Partner
1547 44 346

This is an accepted solution.

@andylewie I've updated the GitHub code to support multiple instances. Please have a look at https://github.com/mirceapiturca/Sections/tree/master/FAQ

Here is a quick demo with 2 instances added on one page: https://machinelearning.myshopify.com/pages/faq?view=contact

 

There are also a few other features added:

- Expose additional max-width, margin-top, margin-bottom settings
- Toggle FAQ Rich Schema

 

Please let me know if you see any issues. 

Thanks

Finally—Add variant descriptions to your products

View solution in original post

Replies 16 (16)

andylewie
Excursionist
20 0 2

I have figured out that the following code in the .js file is only returning the section ID for the first section, so the javascript never gets applied to the subsequent FAQ sections on that page.

 

How do I update this so it returns successive section IDs each time the .js file runs please?

 

function getConfig() {
    return JSON.parse(document.querySelector('[data-faq-config]').innerHTML);
}
  

 

@Mircea_Piturca any tips for your code please?

Mircea_Piturca
Shopify Partner
1547 44 346

Hi @andylewie ,

Sorry for the delay. Please let me have a look into this and I will get back to you today or tomorrow.

Thanks 

Finally—Add variant descriptions to your products

LitCommerce
Astronaut
2860 684 742

Hi @andylewie,

It may have the same ID, that's why the code doesn't work.

Please send me the code you added, I will help you check it

LitCommerce - The Most Simple & Affordable Multi-channel Selling Tool.
Effortlessly sell on biggest marketplaces like Amazon, Etsy, eBay, Facebook etc with bulk listing tool, real-time sync & smart order management. Use LitCommerce free for 1-year now!
andylewie
Excursionist
20 0 2

Hi @LitCommerce , the code is in the following link:

https://github.com/mirceapiturca/Sections/tree/master/FAQ

 

The different sections all have unique IDs, but only the first ID is being returned as per the above post.

Cheers

Mircea_Piturca
Shopify Partner
1547 44 346

This FAQ component was designed to only work for 1 instance, 1 section per page. This is because this component contains Google's FAQ rich snippet schema that can be only included once per page.

 

It should be possible to make it work on multiple sections per page. I will do my best to make this happened this week.

 

Cheers

 

 

Finally—Add variant descriptions to your products
andylewie
Excursionist
20 0 2

Thanks a lot @Mircea_Piturca , your code is the best example I can find online so if it can be expanded across multiple sections that would be amazing. Having it integrated into the theme editor, including rich snippets, and having it relatively lightweight is much better than others I've experimented with.

LitCommerce
Astronaut
2860 684 742

Hi @andylewie,

Please follow the steps below:

- Step 1: Go to sections > faq.liquid file and remove code here:

Screenshot.png

- Step 2: Go to layout > theme.liquid file and add code above '</head>' tag.

Screenshot.png

Hope it helps!

LitCommerce - The Most Simple & Affordable Multi-channel Selling Tool.
Effortlessly sell on biggest marketplaces like Amazon, Etsy, eBay, Facebook etc with bulk listing tool, real-time sync & smart order management. Use LitCommerce free for 1-year now!
Mircea_Piturca
Shopify Partner
1547 44 346

@andylewie Please see @LitCommerce solution.

The faq.js needs to be included only once. Please make the suggested changes and let me know if all is OK.

 

Thank you

Finally—Add variant descriptions to your products
andylewie
Excursionist
20 0 2

I had already tried that, but unfortunately it doesn't solve the issue.

 

In faq.js the getConfig() function still only returns the first FAQ section, so the subsequent FAQ sections are never being returned and hence never getting the javascript applied to them.

andylewie
Excursionist
20 0 2

Hi @LitCommerce  and @Mircea_Piturca , thank you for your help so far.

Hope the attached screenshots help to show what is happening, showing that I've got multiple FAQ sections separated by headings and the like.

Screen Shot 2022-03-30 at 7.03.52 AM.png

Screen Shot 2022-03-30 at 7.05.21 AM.png

  

LitCommerce
Astronaut
2860 684 742

Hi @andylewie,

You can make me a staff account, I will help you debug it

LitCommerce - The Most Simple & Affordable Multi-channel Selling Tool.
Effortlessly sell on biggest marketplaces like Amazon, Etsy, eBay, Facebook etc with bulk listing tool, real-time sync & smart order management. Use LitCommerce free for 1-year now!
andylewie
Excursionist
20 0 2

Hi @LitCommerce , I think I'm nearly there but thanks for the offer. I added a for loop at the top and a counter "faqIndex" which is really ugly coding, but is about the extent of my skills. Here is the updated faq.js:

 

(function FAQ(SD) {
  'use strict';
  
  var support = getSupport();
  var faqIndex = 0;
  
  for (faqIndex = 0; faqIndex < document.querySelectorAll('[data-faq-config]').length; faqIndex++) {
  
    var config = getConfig();
    var init = compose(publicAPI, setEvents, getBlocks, getConfig);

    SD.faq = {}
    SD.faq[config.sectionId] = init();

    function publicAPI(config) {
      return {
        id: config.sectionId,
        config: config,
        blocks: zipObj(config.blockIds, config.blocks),
        init: init
      }
    }
  }

  //**************************


  /**
   * Click event.
   * @param {Object} block Section block elements and methods.
   * @return {Object} Section block elements and methods.
   */
  function blockEvents(block) {
    block.trigger.addEventListener('click', function triggerClick() {
      toggle(block);
    });

    return block;
  }

  /**
   * Toggle block state.
   * @param {Object} block Section block elements and methods.
   * @return {Object} Section block elements and methods.
   */
  function toggle(block) {
    block.collapsed ? expand(block) : collapse(block);
    return block;
  }
  
  /**
   * Expand block.
   * @param {Object} block Section block elements and methods.
   * @return {Object} Section block elements and methods.
   */
  function expand(block) {
    block.button.setAttribute('aria-expanded', true);
    block.panel.removeAttribute('hidden');
    animate(block.panel, 'normal');
    return block;
  }
  
  /**
   * Collapse block.
   * @param {Object} block Section block elements and methods.
   * @return {Object} Section block elements and methods.
   */
  function collapse(block) {
    block.button.setAttribute('aria-expanded', false);
    block.panel.setAttribute('hidden', '');
    animate(block.panel, 'reverse');
    return block;
  }
  
  /**
   * Collapse block.
   * @param {Object} block Section block elements and methods.
   * @return {boolean} Collapsed block state.
   */
  function isCollapsed(block) {
    return Boolean(block.button.getAttribute('aria-expanded') === 'false');
  }

  /**
   * Collapse block.
   * @param {HTMLElement} element Block panel element to animate.
   * @param {String} direction Animation direction, normal or reverse.
   * @return {undefined} Nothing to return.
   */
  function animate(element, direction) { 
    if (!support.WebAnimations) return;

    element.setAttribute('data-is-animating', true);

    element.animate([
      { height: 0 },
      { height: element.offsetHeight + 'px' }],

      { duration: 240,
        fill: 'both',
        easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',
        direction: direction
      }

    ).onfinish = function() {
      element.removeAttribute('data-is-animating');
      this.cancel();
    };
  }

  //**************************


  /**
   * Maps all block IDs to exposed block API.
   * @param {Object} config Section and section blocks IDs.
   * @return {Object} config Section and section blocks IDs.
   */
  function getBlocks(config) {
    config.blocks = config.blockIds.map(block);
    return config;
  }

  /**
   * Create section block API.
   * @param {String} blockId Section Liquid block ID.
   * @return {Object} block elements and methods.
   */
  function block(blockId) {
    return {
      trigger: document.querySelector('[data-faq-trigger="' + blockId + '"]'),
      button: document.querySelector('[data-faq-button="' + blockId + '"]'),
      panel: document.querySelector('[data-faq-panel="' + blockId + '"]'),

      get collapsed() { return isCollapsed(this) },
      select: function select() { return expand(this) },
      deselect: function deselect() { return collapse(this) }
    }
  }

  /**
   * Adds event listeners to block elements.
   * @param {Object} config Section and section blocks IDs.
   * @return {Object} config Section and section blocks IDs.
   */
  function setEvents(config) {
    config.blocks.forEach(blockEvents);
    return config;
  }

  /**
   * Pass the Liquid assigned section variabiles.
   * @param {String} sectionId Current section ID.
   * @return {Object} Section and section blocks IDs.
   */
  function getConfig() {
    return JSON.parse(document.querySelectorAll('[data-faq-config]').item(faqIndex).innerHTML);
  }

  /**
   * Feature detection.
   * @return {Object} Browser support.
   */
  function getSupport() {
    return {
      WebAnimations: (typeof Element.prototype.animate === 'function')
    }
  }

  //**************************


  /**
   * Creates a new object out of a list of keys and a list of values.
   * Key/value pairing is truncated to the length of the shorter of the two lists.
   * @example
   *    zipObj(['a', 'b', 'c'], [1, 2, 3]); //=> {a: 1, b: 2, c: 3}
   * @param {Array} keys The array that will be properties on the output object.
   * @param {Array} values The list of values on the output object.
   * @return {Object} The object made by pairing up same-indexed elements of `keys` and `values`.
   */
  function zipObj(keys, values) {
    return keys.reduce(
      function zipObj(acc, key, idx) {
        acc[key] = values[idx];
        return acc;
      }, {}
    )
  }

  /**
   * Performs right-to-left function composition.
   * The rightmost function may have any arity, the remaining functions must be unary.
   * @example
   *   function plus1(n) {return n + 1};
   *   function plus2(n) {return n + 2};
   *   compose(plus2,plus1)(1) => 4
   * @return {Function} Composed function
   */
  function compose() {
    var funcs = Array.prototype.slice.call(arguments).reverse();
    return function() {
      return funcs.slice(1).reduce(function(res, fn) {
        return fn(res);
      }, funcs[0].apply(undefined, arguments));
    };
  }
  
})(window.SectionsDesign = window.SectionsDesign || {});

 

 

Now I'll try figure out the rich data in faq.liquid

Mircea_Piturca
Shopify Partner
1547 44 346

This is an accepted solution.

@andylewie I've updated the GitHub code to support multiple instances. Please have a look at https://github.com/mirceapiturca/Sections/tree/master/FAQ

Here is a quick demo with 2 instances added on one page: https://machinelearning.myshopify.com/pages/faq?view=contact

 

There are also a few other features added:

- Expose additional max-width, margin-top, margin-bottom settings
- Toggle FAQ Rich Schema

 

Please let me know if you see any issues. 

Thanks

Finally—Add variant descriptions to your products
andylewie
Excursionist
20 0 2

Works percetly, thank you very much!

Mircea_Piturca
Shopify Partner
1547 44 346

Happy to hear that.

Feel free to submit bugs and improvements at https://github.com/mirceapiturca/Sections/tree/master/FAQ

 

Thanks

Finally—Add variant descriptions to your products
Arian1111
Visitor
1 0 0

Hello @Mircea_Piturca, I have installed your FAQ into my Shopify store. 
I am really happy with it overall, but I have 2 problems.

First problem, I can choose whichever color I want for the question and answer text, but it doesn't change anything. The question color remains black and the answer color remains dark grey. 

The second problem is just with a iphone. When I want to open the FAQ page on my iphone, the question color and the "+" and "-" for dropdown are blue colored, which I can also not change. The answer color remains dark grey. And this just happens on a iphone, all other devices display black question color and dark grey answer color.

Do you happen to have a solution to this problems? I would be very grateful.

I am using the Refresh theme.