CMS Load More - Infinite, newly loaded items GSAP interaction doesn't work

I’m using the infinite load optional feature for a large list of newsfeed cards. Each card has a CTA button which has a GSAP hover interaction and it works on the cards that initially load with the page but the interaction doesn’t work on any of the items that is loaded as you scroll further down the page. The link still works and will open the new page, just the hover interaction isn’t working.

Here is the page on the staging site that this is happening on: https://skycar.webflow.io/newsfeed

Here is the read-only link for the page where I’ve implemented the solution in the Webflow Project:
Read-only link

I’m using a solution for the GSAP interaction from Timothy Ricks found here: GSAP Interaction

Hey @michaellee2245! Can you share the snippet used to initiate the Gsap?

Tha solution would be to add the CMS Load callback and rerun the snippet once new items are rendered on page.

Here is the callback in case you want to give it a shot

window.fsAttributes = window.fsAttributes || [];
window.fsAttributes.push([
  'cmsload',
  (listInstances) => {
    console.log('cmsload Successfully loaded!');

    // The callback passes a `listInstances` array with all the `CMSList` instances on the page.
    const [listInstance] = listInstances;

    // The `renderitems` event runs whenever the list renders items after switching pages.
    listInstance.on('renderitems', (renderedItems) => {
      console.log(renderedItems);
    });
  },
]);

Sorry for the late reply Luis. Here is the GSAP code that initiates the clip path hover effect:

// Button Clip Path Hover
$("[data-btn='wrap']").each(function () {
  const clipEl = $(this).find("[data-btn='clip']").attr("aria-hidden", "true");
  const durationSetting = 0.4;
  const easeSetting = "power2.out";

  function getPercentTop(el, e) {
    let elTop = el.offset().top - $(window).scrollTop();
    let mouseTop = e.pageY - $(window).scrollTop() - elTop;
    return (mouseTop / el.innerHeight()) * 100;
  }

  function getPercentLeft(el, e) {
    let elLeft = el.offset().left;
    let mouseLeft = e.pageX - elLeft;
    return (mouseLeft / el.innerWidth()) * 100;
  }
  $(this).on("mouseenter", function (e) {
    let percentTop = getPercentTop($(this), e);
    let percentLeft = getPercentLeft($(this), e);
    gsap.set(clipEl, { display: "flex" });
    gsap.fromTo(
      clipEl, { clipPath: `circle(0% at ${percentLeft}% ${percentTop}%)` }, {
        clipPath: `circle(141.4% at ${percentLeft}% ${percentTop}%)`,
        duration: durationSetting,
        ease: easeSetting
      });
  });
  $(this).on("mouseleave", function (e) {
    let percentTop = getPercentTop($(this), e);
    let percentLeft = getPercentLeft($(this), e);
    gsap.to(clipEl, {
      clipPath: `circle(0% at ${percentLeft}% ${percentTop}%)`,
      overwrite: true,
      duration: durationSetting,
      ease: easeSetting
    });
  });
});

Would I just use the callback in script tags before the closing body tag in the custom code? I don’t need to add it to an existing function or anything right? Thanks for your help!

Hey @michaellee2245! That is correct, the added callback should go in the </body> section of the custom code. I see you are using Slater, the callback may also be added there.

I can’t test the code at the moment because disabling the Slater script breaks the page on my end but please test and let me know.

I moved the code to a function called gsapInit that is called when CMS Load is done loading and each time new items are rendered. This should query all newly rendered data-button='wrap' and re-initiate the hover effect.

window.fsAttributes = window.fsAttributes || [];
window.fsAttributes.push([
  'cmsload',
  (listInstances) => {
    console.log('cmsload Successfully loaded!');

    const [listInstance] = listInstances;

    const gsapInit = function() {
      const clipEl = $(this).find("[data-btn='clip']").attr('aria-hidden', 'true');
      const durationSetting = 0.4;
      const easeSetting = 'power2.out';

      const getPercentTop = (el, e) => {
        let elTop = el.offset().top - $(window).scrollTop();
        let mouseTop = e.pageY - $(window).scrollTop() - elTop;
        return (mouseTop / el.innerHeight()) * 100;
      }

      const getPercentLeft = (el, e) => {
        let elLeft = el.offset().left;
        let mouseLeft = e.pageX - elLeft;
        return (mouseLeft / el.innerWidth()) * 100;
      }

      $(this).on('mouseenter', function(e) {
        let percentTop = getPercentTop($(this), e);
        let percentLeft = getPercentLeft($(this), e);
        gsap.set(clipEl, { display: 'flex' });
        gsap.fromTo(
          clipEl,
          { clipPath: `circle(0% at ${percentLeft}% ${percentTop}%)` },
          {
            clipPath: `circle(141.4% at ${percentLeft}% ${percentTop}%)`,
            duration: durationSetting,
            ease: easeSetting,
          }
        );
      });

      $(this).on('mouseleave', function(e) {
        let percentTop = getPercentTop($(this), e);
        let percentLeft = getPercentLeft($(this), e);
        gsap.to(clipEl, {
          clipPath: `circle(0% at ${percentLeft}% ${percentTop}%)`,
          overwrite: true,
          duration: durationSetting,
          ease: easeSetting,
        });
      });
    };

    // Button Clip Path Hover
    $("[data-btn='wrap']").each(gsapInit);

    listInstance.on('renderitems', (renderedItems) => {
      console.log(renderedItems);
      $("[data-btn='wrap']").each(gsapInit);
    });
  },
]);

1 Like