javascriptgsapscrolltrigger

Run ScrollTrigger animation once (once: true not working)


I have an ScrollTrigger animation which I only want running once.

As per the docs, "If true, the ScrollTrigger will kill() itself as soon as the end position is reached once."

However, in my case, when I add once: true, I get the message "Invalid property", "once", "set to", true, "Missing plugin? gsap.registerPlugin()" in console, when I've registered the plugin already?

$(function() {

  gsap.registerPlugin(ScrollTrigger);

  function animateFrom(elem, direction) {
    direction = direction || 1;

    var x = 0,
      y = direction * 100;
    if (elem.classList.contains("gsap_reveal--fromLeft")) {
      x = -100;
      y = 0;
    } else if (elem.classList.contains("gsap_reveal--fromRight")) {
      x = 100;
      y = 0;
    }

    elem.style.transform = "translate(" + x + "px, " + y + "px)";
    elem.style.opacity = "0";

    gsap.fromTo(elem, {
      x: x,
      y: y,
      autoAlpha: 0
    }, {
      duration: 2,
      x: 0,
      y: 0,
      autoAlpha: 1,
      ease: "expo",
      overwrite: "auto",
      once: true, // doesnt work
    });

  }

  function hide(elem) {
    gsap.set(elem, {
      autoAlpha: 0
    });
  }

  gsap.utils.toArray(".gsap_reveal").forEach(function(elem) {
    hide(elem); // assure that the element is hidden when scrolled into view
    ScrollTrigger.create({
      trigger: elem,
      onEnter: function() {
        animateFrom(elem)
      },
      onEnterBack: function() {
        animateFrom(elem, -1)
      },
      onLeave: function() {
        hide(elem)
      } // assure that the element is hidden when scrolled into view
    });
  });

});
.hero {
  min-height: 400px;
  background: lightblue;
  display: flex;
  align-items: center;
}

.textImageRepeater {
  overflow: hidden;
  padding: 120px 0 160px 0;
}
.textImageRepeater__intro {
  margin-bottom: 66px;
}
.textImageRepeater__layout--row {
  flex-direction: row !important;
}
.textImageRepeater__layout--rowReverse {
  flex-direction: row-reverse !important;
}
.textImageRepeater__item {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  padding-top: 70px;
  justify-content: space-between;
}
.textImageRepeater__header {
  margin: 17px 0;
}
.textImageRepeater__graphic {
  margin: 0;
}
.textImageRepeater__text, .textImageRepeater__graphic {
  flex-basis: 50%;
}
.textImageRepeater__text {
  max-width: 500px;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js"></script>

<div class="scroll-section" data-scroll-container>
  <div data-scroll-section>

    <section class="hero">
      <div class="container">
        <div class="row justify-content-center justify-content-xl-between">
          <div class="col-12 col-md-10 col-lg-9 col-xl-5">
            <div class="hero__text text-center text-xl-start">
              <h1 class="hero__title">Title</h1>
            </div>
          </div>
        </div>
      </div>
    </section>

    <section class="textImageRepeater">
      <div class="container">
        <div class="row">
          <div class="col-12">

            <div class="textImageRepeater__item textImageRepeater__layout--row">
              <div class="textImageRepeater__text text-center text-md-start gsap_reveal gsap_reveal--fromRight">
                <div class="textImageRepeater__copy">
                  <h2>Header</h2>
                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
                </div>
              </div>
              <div class="textImageRepeater__graphic text-center gsap_reveal gsap_reveal--fromLeft">
                <img class="textImageRepeater__image" src="https://picsum.photos/200/300" alt="placeholder-image" loading="lazy">
              </div>
            </div>

            <div class="textImageRepeater__item textImageRepeater__layout--rowReverse">
              <div class="textImageRepeater__text text-center text-md-start gsap_reveal gsap_reveal--fromRight">
                <div class="textImageRepeater__copy">
                  <h2>Header</h2>
                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
                </div>
              </div>
              <div class="textImageRepeater__graphic text-center gsap_reveal gsap_reveal--fromLeft">
                <img class="textImageRepeater__image" src="https://picsum.photos/200/300" alt="placeholder-image" loading="lazy">
              </div>
            </div>

          </div>
        </div>
      </div>
    </section>


Solution

  • $(function() {
    
      gsap.registerPlugin(ScrollTrigger);
    
      function animateFrom(elem, direction) {
        direction = direction || 1;
    
        var x = 0,
          y = direction * 100;
        if (elem.classList.contains("gsap_reveal--fromLeft")) {
          x = -100;
          y = 0;
        } else if (elem.classList.contains("gsap_reveal--fromRight")) {
          x = 100;
          y = 0;
        }
    
        elem.style.transform = "translate(" + x + "px, " + y + "px)";
        elem.style.opacity = "0";
    
        gsap.fromTo(elem, {
          x: x,
          y: y,
          autoAlpha: 0
        }, {
          duration: 2,
          x: 0,
          y: 0,
          autoAlpha: 1,
          ease: "expo",
          overwrite: "auto",
        });
    
      }
    
      function hide(elem) {
        gsap.set(elem, {
          autoAlpha: 0
        });
      }
    
      gsap.utils.toArray(".gsap_reveal").forEach(function(elem) {
        hide(elem); // assure that the element is hidden when scrolled into view
        ScrollTrigger.create({
          once: true,
          trigger: elem,
          onEnter: function() {
            animateFrom(elem)
          },
          onEnterBack: function() {
            animateFrom(elem, -1)
          },
          onLeave: function() {
            hide(elem)
          } // assure that the element is hidden when scrolled into view
        });
      });
    
    });
    .hero {
      min-height: 400px;
      background: lightblue;
      display: flex;
      align-items: center;
    }
    
    .textImageRepeater {
      overflow: hidden;
      padding: 120px 0 160px 0;
    }
    .textImageRepeater__intro {
      margin-bottom: 66px;
    }
    .textImageRepeater__layout--row {
      flex-direction: row !important;
    }
    .textImageRepeater__layout--rowReverse {
      flex-direction: row-reverse !important;
    }
    .textImageRepeater__item {
      display: flex;
      align-items: center;
      justify-content: center;
      flex-direction: column;
      padding-top: 70px;
      justify-content: space-between;
    }
    .textImageRepeater__header {
      margin: 17px 0;
    }
    .textImageRepeater__graphic {
      margin: 0;
    }
    .textImageRepeater__text, .textImageRepeater__graphic {
      flex-basis: 50%;
    }
    .textImageRepeater__text {
      max-width: 500px;
    }
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js"></script>
    
    <div class="scroll-section" data-scroll-container>
      <div data-scroll-section>
    
        <section class="hero">
          <div class="container">
            <div class="row justify-content-center justify-content-xl-between">
              <div class="col-12 col-md-10 col-lg-9 col-xl-5">
                <div class="hero__text text-center text-xl-start">
                  <h1 class="hero__title">Title</h1>
                </div>
              </div>
            </div>
          </div>
        </section>
    
        <section class="textImageRepeater">
          <div class="container">
            <div class="row">
              <div class="col-12">
    
                <div class="textImageRepeater__item textImageRepeater__layout--row">
                  <div class="textImageRepeater__text text-center text-md-start gsap_reveal gsap_reveal--fromRight">
                    <div class="textImageRepeater__copy">
                      <h2>Header</h2>
                      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
                    </div>
                  </div>
                  <div class="textImageRepeater__graphic text-center gsap_reveal gsap_reveal--fromLeft">
                    <img class="textImageRepeater__image" src="https://picsum.photos/200/300" alt="placeholder-image" loading="lazy">
                  </div>
                </div>
    
                <div class="textImageRepeater__item textImageRepeater__layout--rowReverse">
                  <div class="textImageRepeater__text text-center text-md-start gsap_reveal gsap_reveal--fromRight">
                    <div class="textImageRepeater__copy">
                      <h2>Header</h2>
                      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
                    </div>
                  </div>
                  <div class="textImageRepeater__graphic text-center gsap_reveal gsap_reveal--fromLeft">
                    <img class="textImageRepeater__image" src="https://picsum.photos/200/300" alt="placeholder-image" loading="lazy">
                  </div>
                </div>
    
              </div>
            </div>
          </div>
        </section>

    I think you put the argument in the wrong section. You have to put 'once' inside create