tsParticles not defined even though it is

AI-generated summary

tsParticles not defined even though it is

NateDhaliwal is trying to use the tsParticles ‘links’ animation in a Discourse theme, but the console is throwing a “ReferenceError: tsParticles is not defined” error, despite tsParticles being clearly defined at the top of the code.

Alteras suggests that this is a race condition issue, where tsParticles.load() is running before the tsParticles JavaScript has finished loading. To fix this, Alteras recommends either pulling out the code to make a script tag for tsParticles and making it an actual script tag to load with the page, or running the code on the load event.

NateDhaliwal confirms that Alteras’ solution works, and thanks them for their help. The corrected code involves creating a script element, adding a load event listener, and then appending the script to the head of the document, like this:

const script = document.createElement('script');
script.addEventListener("load", () => {
  console.log("called", tsParticles);
  initTsParticles();
})
script.src = "https://cdn.jsdelivr.net/npm/@tsparticles/preset-links@3.0.2/tsparticles.preset.links.bundle.min.js";
document.head.appendChild(script);

function initTsParticles() {
  tsParticles.load({
    ...
  });
}

I am trying to put the tsParticles ‘links’ animation in my Discourse theme.
However, the Console says that:

theme-field-96515-common-html-script-1.js:36 Uncaught (in promise) ReferenceError: tsParticles is not defined
    at theme-field-96515-common-html-script-1.js:36:13
    at HTMLDocument.<anonymous> (theme-field-96515-common-html-script-1.js:36:13)

But you can see that in my code, it clearly is, at the top.
Here is my code:

<script type="text/discourse-plugin" version="1.14.0">
  var script = document.createElement('script');
  script.src = "https://cdn.jsdelivr.net/npm/@tsparticles/preset-links@3.0.2/tsparticles.preset.links.bundle.min.js";
  document.head.appendChild(script);
  const showLinks = settings.show_tsParticles_links_animation;
  if (showLinks) {
    document.addEventListener("DOMContentLoaded", function() {
      var elements = document.querySelectorAll('section#main');
      elements.forEach(function(el) {
        var wrapper = document.createElement('div');
        wrapper.className = 'wrapper';
        el.parentNode.insertBefore(wrapper, el);
        wrapper.appendChild(el);
      });
      var elements = document.querySelectorAll('div#main-outlet-wrapper');
      elements.forEach(function(el) {
        var wrapper = document.createElement('div');
        wrapper.className = 'content';
        el.parentNode.insertBefore(wrapper, el);
        wrapper.appendChild(el);
      });
      
      (async () => {
        await tsParticles.load({
          id: "tsparticles",
          options: { preset: "links" },
          background: {
            "color": {"value":"#0d47a1"}
          }
        });
      })();
    });
  }
</script>

Moreover, when looking at he <head> of the page, this tag is there.

Looks like a race condition where the tsParticles.load() is running before the js has finished loading.

Since you’re already in the <head> element, you can probably just pull out the code for making a script tag for tsParticles, and just make it an actual script tag so that it loads with the page instead of after page load finishes.

If you need to keep the script load in the JS, you can run the code on the load event.

const script = document.createElement('script');
script.addEventListener("load", () => {
      console.log("called", tsParticles);
      initTsParticles();
  })
script.src = "https://cdn.jsdelivr.net/npm/@tsparticles/preset-links@3.0.2/tsparticles.preset.links.bundle.min.js";
document.head.appendChild(script);

function initTsParticles() {
  tsParticles.load({
    ...
  });
}

That works, thanks so much!