3

Is there a way I can wrap an external JS script embed with lazy-load behavior to only execute when the embed is in the viewport?

Context: I have an external javascript embed that when run, generates an iframe with a scheduling widget. Works pretty well, except that when the script executes, it steals focus and scrolls you down to the widget when it’s done executing. The vendor has been looking at a fix for a couple weeks, but it’s messing up my pages. I otherwise like the vendor.

Javascript embed call:

<a href=https://10to8.com/book/zgdmlguizqqyrsxvzo/ id="TTE-871dab0c-4011-4293-bee3-7aabab857cfd" target="_blank">See
    Online Booking Page</a>
<script src=https://d3saea0ftg7bjt.cloudfront.net/embed/js/embed.min.js> </script> <script>
    window.TTE.init({
        targetDivId: "TTE-871dab0c-4011-4293-bee3-7aabab857cfd",
        uuid: "871dab0c-4011-4293-bee3-7aabab857cfd",
        service: 1158717
    });
</script>

While I'm waiting for the vendor to fix their js, I wondered if lazy-loading the JS embed may practically eliminate the poor user experience. Warning: I'm a JS/webdev noob, so probably can't do anything complicated. A timer-based workaround is not ideal because users may still be looking at other parts of the page when the timer runs out. Here are the things I’ve tried and what happens:

I tried: What happened:
Add async to one or both of the script declarations above Either only shows the link or keeps stealing focus.
Adding type=”module” to one or both script declarations above Only rendered the link.
Wrapping the above code in an iframe with the appropriate lazy-loading tags When I tried, it rendered a blank space.

Also, I realize it's basically the same question as this, but it didn't get any workable answers.

Dylan
  • 33
  • 1
  • 1
  • 3
  • 2
    This would be a multi-step process and you'd have to make some decisions. You can write some javascript to detect when the user has scrolled to a certain point, or when a certain element comes in the viewport, and only then insert the ` – TKoL May 11 '21 at 13:16
  • 2
    Does this answer your question? [Trigger a function when the user scrolls the element into the viewport – Vanilla JavaScript](https://stackoverflow.com/questions/54629590/trigger-a-function-when-the-user-scrolls-the-element-into-the-viewport-vanilla) – Heretic Monkey May 11 '21 at 13:17
  • But the problem with this is that if you wait too long, then they may have scrolled past that point by the time the code runs and the script loads. – TKoL May 11 '21 at 13:17
  • Hi Dylan, this should help you out .... https://stackoverflow.com/questions/950087/how-do-i-include-a-javascript-file-in-another-javascript-file or https://stackoverflow.com/questions/30033152/how-does-lazy-module-loading-work-in-es6 – fuzzybear May 11 '21 at 13:23
  • You may could try out https://creativelive.github.io/appear/ which is a JS lib that can help you trigger the JS code to A) create the *script* tag which will load the vendor's script in the page (use a variable to do it only once) and then B) call the init function with the init params which you can build based on the attributes of the `` tag. – Patrick Janser May 11 '21 at 13:28

2 Answers2

0

I actually also speak french but I'll reply in english for everybody.

Your question was quite interesting because I also wanted to try out some lazy loading so I had a play on Codepen with your example (using your booking id).

I used the appear.js library because I didn't really want to spend time trying some other APIs (perhaps lighter so to take in consideration).

The main JS part I wrote is like this:

// The code to init the appear.js lib and add our logic for the booking links.
(function(){
  // Perhaps these constants could be put in the generated HTML. I don't really know
  // where they come from but they seem to be related to an account.
  const VENDOR_LIB_SRC = "https://d3saea0ftg7bjt.cloudfront.net/embed/js/embed.min.js";
  const UUID = "871dab0c-4011-4293-bee3-7aabab857cfd";
  const SERVICE = 1158717;
  
  let vendorLibLoaded = false; // Just to avoid loading several times the vendor's lib.

  appear({
    elements: function() {
      return document.querySelectorAll('a.booking-link');
    },
    appear: function(bookingLink) {
      console.log('booking link is visible', bookingLink);
      
      /**
       * A function which we'll be able to execute once the vendor's
       * script has been loaded or later when we see other booking links
       * in the page.
       */
      function initBookingLink(bookingLink) {
        window.TTE.init({
          targetDivId: bookingLink.getAttribute('id'),
          uuid: UUID,
          service: SERVICE
        });
      }
      
      if (!vendorLibLoaded) {
        // Load the vendor's JS and once it's loaded then init the link.
        let script = document.createElement('script');
        script.onload = function() {
          vendorLibLoaded = true;
          initBookingLink(bookingLink);
        };
        script.src = VENDOR_LIB_SRC;
        document.head.appendChild(script);
      } else {
        initBookingLink(bookingLink);
      }
    },
    
    reappear: false
  });
})();

I let you try my codepen here: https://codepen.io/patacra/pen/gOmaKev?editors=1111

Tell me when to delete it if it contains sensitive data!

Kind regards,

Patrick

Patrick Janser
  • 3,318
  • 1
  • 16
  • 18
0

This method will Lazy Load HTML Elements only when it is visible to User, If the Element is not scrolled into viewport it will not be loaded, it works like Lazy Loading an Image.

Add LazyHTML script to Head.

<script async src="https://cdn.jsdelivr.net/npm/lazyhtml@1.0.0/dist/lazyhtml.min.js" crossorigin="anonymous" debug></script>

Wrap Element in LazyHTML Wrapper.

<div class="lazyhtml" data-lazyhtml onvisible>
<script type="text/lazyhtml">
      <!--
       <a href=https://10to8.com/book/zgdmlguizqqyrsxvzo/ id="TTE-871dab0c-4011-4293-bee3-7aabab857cfd" target="_blank">See
      Online Booking Page</a>
      <script src=https://d3saea0ftg7bjt.cloudfront.net/embed/js/embed.min.js>
   </script> 
   <script>
      window.TTE.init({
      targetDivId: "TTE-871dab0c-4011-4293-bee3-7aabab857cfd",
      uuid: "871dab0c-4011-4293-bee3-7aabab857cfd",
      service: 1158717
      });
   </script>
   -->
</script>
</div>
Niresh
  • 611
  • 5
  • 16