Streaming live at 10am (PST)

How To Trigger A Script?

I’m lazy loading a div that is reliant on two scripts - One in the body and one inline.

The issue I have is the scripts are firing before the div has loaded in, meaning that function isn’t working.

Can someone help (I am a novice) suggest a way, perhaps a trigger, so when my lazy load div is loaded, only then does it trigger the inline script and script in the body?

I’m using this code for the lazy load:

    <!-- lazysizes v5.1.0 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.0/lazysizes.min.js"></script>
<script>
!function(a,b){var c=function(){b(a.lazySizes),a.removeEventListener("lazyunveilread",c,!0)};b=b.bind(null,a,a.document),"object"==typeof module&&module.exports?b(require("lazysizes")):a.lazySizes?c():a.addEventListener("lazyunveilread",c,!0)}(window,function(a,b,c){"use strict";var d={nodeName:""},e=!!a.HTMLPictureElement&&"sizes"in b.createElement("img"),f=a.lazySizes&&c.cfg,g=function(a){var b,f,g,h,i,j=a.target.querySelectorAll("img, iframe");for(b=0;b<j.length;b++)f=j[b].getAttribute("srcset")||"picture"==(j[b].parentNode||d).nodeName.toLowerCase(),!e&&f&&c.uP(j[b]),j[b].complete||!f&&!j[b].src||(a.detail.firesLoad=!0,h&&i||(i=0,h=function(b){i--,b&&!(i<1)||g||(g=!0,a.detail.firesLoad=!1,c.fire(a.target,"_lazyloaded",{},!1,!0)),b&&b.target&&(b.target.removeEventListener("load",h),b.target.removeEventListener("error",h))},setTimeout(h,3500)),i++,j[b].addEventListener("load",h),j[b].addEventListener("error",h))};f.getNoscriptContent=function(a){return a.textContent||a.innerText},a.addEventListener("lazybeforeunveil",function(a){if(a.detail.instance==c&&!a.defaultPrevented&&null!=a.target.getAttribute("data-noscript")){var b=a.target.querySelector('noscript, script[type*="html"]')||{},d=f.getNoscriptContent(b);d&&(a.target.innerHTML=d,g(a))}})});
</script> 

You the wrap the div you want to lazy load in this:

    <div class="lazyload" data-noscript="">
<noscript>    


</noscript>
</div>

Here is the Shopify Button code that needs to be delayed/triggered:

<div id='product-component-'></div>
<script type="text/javascript">
/*<![CDATA[*/
(function () {
  var scriptURL = 'https://sdks.shopifycdn.com/buy-button/latest/buy-button-storefront.min.js';
  if (window.ShopifyBuy) {
    if (window.ShopifyBuy.UI) {
      ShopifyBuyInit();
    } else {
      loadScript();
    }
  } else {
    loadScript();
  }
  function loadScript() {
    var script = document.createElement('script');
    script.async = true;
    script.src = scriptURL;
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(script);
    script.onload = ShopifyBuyInit;
  }
  function ShopifyBuyInit() {
    var client = ShopifyBuy.buildClient({
      domain: 'hiddenforprivacy.myshopify.com',
      storefrontAccessToken: 'hiddenforprivacy',
    });
    ShopifyBuy.UI.onReady(client).then(function (ui) {
      ui.createComponent('product', {
        id: '',
        node: document.getElementById('product-component-'),
        moneyFormat: '%C2%A3%7B%7Bamount%7D%7D',
        options : {
  product: {
    iframe: false
  },
  cart: {
    iframe: false
  }
}
      });
    });
  }
})();
/*]]>*/
</script>

And here is the Mixitup filter code:

    <!-- Mixitup Filter -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mixitup/3.3.0/mixitup.min.js"></script>
<script src="https://www.hiddenforprivacy.com/mixitup-pagination.min.js"></script>
<script src="https://www.hiddenforprivacy.com/mixitup-multifilter.min.js"></script>
<script>    

  // Reusable function to convert any string/text to css-friendly format
  var conv = function (str) {
    
    return str.replace(/[!\"#$%&'\(\)\*\+,\.\/:;<=>\?\@\[\\\]\^`\{\|\}~]/g, '')
            .replace(/ /g, "-")
              .toLowerCase()
              .trim();
  };
  
  // Creating dynamic elements classes from its categories:
  var catArray = document.querySelectorAll('.w-dyn-item .departures');
  catArray.forEach( function(elem) {
    var text = elem.innerText || elem.innerContent;
    var className = conv(text);
    elem.parentElement.parentElement.classList.add(className);
  });
  
  
     // Creating dynamic elements classes from its destinations:
  var catArray = document.querySelectorAll('.w-dyn-item .destinations');
  catArray.forEach( function(elem) {
    var text = elem.innerText || elem.innerContent;
    var className = conv(text);
    elem.parentElement.parentElement.classList.add(className);
  });
  
  
    // Creating dynamic elements classes from its dates:
  var catArray = document.querySelectorAll('.w-dyn-item .date');
  catArray.forEach( function(elem) {
    var text = elem.innerText || elem.innerContent;
    var className = conv(text);
    elem.parentElement.parentElement.classList.add(className);
  });    

  
  // Creating dynamic elements classes from its journey types:
  var catArray = document.querySelectorAll('.w-dyn-item .type');
  catArray.forEach( function(elem) {
    var text = elem.innerText || elem.innerContent;
    var className = conv(text);
    elem.parentElement.parentElement.classList.add(className);
  });
      

  // Creating a custom data-order attributes from blog titles:
  var sortArray = document.querySelectorAll('.w-dyn-item .price');
  sortArray.forEach( function(sortElem) {
    var sortText = sortElem.innerText || sortElem.innerContent;
    sortElem.parentElement.setAttribute('data-order', sortText);
  });    


  var filterGroups = document.querySelectorAll('.filter-group');
  filterGroups.forEach( function(group) {
        group.setAttribute('data-filter-group','');
  });    


  var containerEl = document.querySelector('.container');
  
  
    var mixer = mixitup(containerEl, {
   pagination: {
       limit: 16,
   },
   
       multifilter: {
         enable: true                 
   }
});    


  var selectSort = document.querySelector('.sort_select'); // defining the sort control for the desktop
  var mobileSort = document.querySelector('.sort_mob'); // defining the sort control for mobile    



// make sure Sorting works on desktop
  selectSort.addEventListener('change', function() {
    var order = selectSort.value;
    mixer.sort(order);
  });    


//making sure Sorting works on mobile  
    mobileSort.addEventListener('change', function() {
    var order = mobileSort.value;
    mixer.sort(order);
  });    

  
</script>

I’ve been stuck on this for two days, so any help would be highly appreciated!

1 Like

Edit: I’ve tweaked my question as I think I have gotten closer to the answer myself, just need some help with the actual code.

1 Like

Any ideas, anyone? :slight_smile:

I’ve learnt a lot building websites through Webflow so far, but Javascript it a little too out of reach for me!

1 Like

what about firing your scripts once the DOM has finished loading so that your DIV has time to loaded properly in the Document Object Model (DOM) ?

document.addEventListener("DOMContentLoaded", () => {
 // functionA();
 // functionB();
});
2 Likes

Hey there :slight_smile:

Sorry for getting back to you so late, I’ve been stalking your question since you’ve posted this.
I had a similar problem with a third-party form I needed to embed, due to GDPR and data privacy I needed to check if the user had opted-in third-party cookies, so I could use the form.

As @anthonysalamin said, you could put the function into an DOM event listener, the shopify button function is a IIFE (Immediately Invoked Function Expression), so it’d fire as soon as it’s parsed.

Let me know if this works for you, I might have another approach for you to try :slight_smile:

2 Likes

@RDaneelOliwav are you from Berlin too ? :slight_smile:

I’m not sure it’s directly related to the original question but I was also struggeling with scripts being loaded depending on wether or not the user had opted in or not to the GDPR cookies… I solved the problem nicely by using CookieHub and Google Tag Manager. The combination of the two let you trigger any third party script based on specific condition (user opted for marketing cookies or analytics cookies or whatever cookie group you specify within your CookieHub accont).

2 Likes

@anthonysalamin and @RDaneelOliwav Thank you both so much for your replies!

Apologies if I sounded impatient… I was on such a role last week and this was the only thing I became stuck on!

Loading a script once a DOM element finishes loading could work… I only want the scripts to fire IF that element is loaded.

@anthonysalamin Could you help me understand what I would need to place in the

//functionA();
//functionB();

sections of the code? I guess function A I would place the script I currently have in the body, but as for function B it’s currently an inline script that loads a price from Shopify. Would I need to wrap the inline code and then place that in the Function B area?

Would I then need to give the DIV a class of “DOMContentLoaded”?

Apologies for my lack of understanding, your help is greatly appreciated! :slight_smile:

1 Like

Hello,

If you want to create and load a script based on the presence or not of a DIV in the DOM you can do the following:

  1. wait for the DOM to finish loading
  2. check if the DIV exists (its variable shouldn’t equal to “null”)
  3. create and load the script if the DIV exists

Here is a quick codepen for you.
JavaScript could look something like this:

document.addEventListener("DOMContentLoaded", () => {
  checkDiv();
});

// checks if div exists
function checkDiv() {
  let div = document.getElementById("div-to-check");
  console.log(div);

  if (div != null) {
    console.log("🥳 Yay the DIV exists in the DOM");
    loadScript();
  } else {
    alert("😭 Ooops the DIV doesn't exist");
  }
}

// create + load script into body
function loadScript() {
  const script = document.createElement("script");
  script.src = "path/to/your/script.js";
  // script.defer = true;
  document.body.appendChild(script);
  console.log(script);
}
2 Likes

Hi @anthonysalamin thank you so much for the nudge in the right direction.

I’ve definitely done something wrong but I can’t figure out what exactly - I’ve pasted in the scripts and given the Div an ID, but I get the error ‘oops the div does not exist’, but surely that’s because it hasn’t loaded yet? The functionality of the Mixitup filter also no longer works.

Would you mind taking a look? The area with the scripts is the Div containing the listings and the filter half way down.

https://preview.webflow.com/preview/luxury-train-tickets?utm_medium=preview_link&utm_source=designer&utm_content=luxury-train-tickets&preview=f9342647edfd8e4db93389692827ab7c&pageId=5ee72644175d3372a46d420f&mode=preview

1 Like

Hey @anthonysalamin :slight_smile:

You don’t see many Hauptstädter around here! Nice to meet you!

I’m currently drafting a post on how to implement a fully custom way to control cookies and scripts in compliance to gdpr without third-party tools. Do you know how Cookiehub defer’s external scripts, especially iframes?

1 Like

mmh not especially iframes but this is how CookieHub could defer ga external script:

window.addEventListener("load", function () {
  const googleAnalytics = "UA-XXXXXXX";
  window.cookieconsent.initialise({
    // 🧠 on initialise
    onInitialise: function (status) {
      if (this.hasConsented("required")) {
      }
      if (this.hasConsented("analytics")) {
        window[`ga-disable-${googleAnalytics}`] = false;
        gtag("config", gtagId);
      }
      if (this.hasConsented("marketing")) {
      }
    },
    // 🧠 on allow
    onAllow: function (category) {
      if (category == "required") {
      }
      if (category == "analytics") {
        window[`ga-disable-${googleAnalytics}`] = false;
        gtag("config", gtagId);
      }
      if (category == "marketing") {
      }
    },
    // 🧠 on revoke
    onRevoke: function (category) {
      if (category == "required") {
      }
      if (category == "analytics") {
        window[`ga-disable-${googleAnalytics}`] = true;
      }
      if (category == "marketing") {
      }
    }
  });
});
1 Like

Ah yes, thanks for sharing!
I knew about the ga-disable-XXXXXXX = true window object, using it myself :slight_smile:

The company I work for uses Webflow video elements as “normal” components in the designer, as well as in cms collections (as fields) and inside rich texts. Webflow uses “embedliefy” (prob. misspelled) JS plus <iframe> elements for the normal components and cms fields but uses <figure>tags plus <iframe> with slightly diff structure for rich texts.

Using that with youtube links automatically creates cookies and sends data to externals, thus meaning problem with gdpr.

I’m working on a guide for this forum on how to cope with all sorts of gdpr problems. So far for those videos, the only reliable solution was to remove all video elements and let the users paste youtube links on the site. Custom JS then replaces the links with actual <iframe> if consent was given ;D
I have experimented lots of things

I also have a really neat way to load any scripts only after consent is given ;D