1

I have to add a script tag via some JavaScript and have it execute in full as the later statements rely on it.

var logIt = (function() {
  var i = 0,
    logging = document.getElementById('logging');
  return function(s) {
    var heading = document.createElement('p');
    heading.innerText = `${++i}:  ${s}`;
    logging.appendChild(heading);
  }
}());

logIt('starting');
var newScriptTag = document.createElement('script');
newScriptTag.src = 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.js';
newScriptTag.type = 'text/javascript';
document.head.appendChild(newScriptTag);
try {
  var now = moment().format('HH:mm');
  logIt(`moment loaded.  The time is ${now}`);
} catch (e) {
  logIt(`Moment not loaded: ${e}`);
}
<html>

<head>
  <title>Injecting Script Tags</title>
</head>

<body>
  <h1>Injecting Script Tags</h1>
  <div id="logging"></div>
</body>

</html>

As the snippet above shows, the moment() isn't available on the statement after the tag insertion.

I think it could be done with eval(...), but that option isn't popular.

2
  • 1
    ever heard of onload? Commented May 20, 2019 at 14:55
  • @GottZ Yes. Due to come compiling/transpiling/compressing/uglification it's not an option though. Commented May 20, 2019 at 15:51

1 Answer 1

3

Use the onload event listener on the <script> tag:

const URL = 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.js';

const onMomentReady = () => {
  console.log('Moment.js is loaded!');
  console.log(typeof moment);
}

var newScriptTag = document.createElement('script');
newScriptTag.onload = onMomentReady;
newScriptTag.src = URL;
// newScriptTag.type = 'text/javascript'; // no need for this

// optional
newScriptTag.async = true;
document.head.appendChild(newScriptTag);

Note that I added the onload handler before setting the src attribute. If you set the src first, the handler function might not fire.

Sign up to request clarification or add additional context in comments.

5 Comments

Doesn't this still run moment async? I can't call moment() in the same script, bar within the onMomentReady() method (and after it's been fired).
Not sure what you expected. Of course, it does run the onMomentReady function asynchronously, because your browser cannot start to load moment before it has loaded, processed & executed the JS which creates the <script> tag. Also, the process of loading does consume time and is therefor async by it's nature – even if you don't put the async attribute onto the <script> tag.
just to add to this: not doing stuff async / event oriented in js is extremely bad practice and considered a anti pattern.
@GottZ I have to work with framework I have and I can't async it because it's there's stuff outside my control that will be bundled into it.
nothing is impossible. and unless you name that "framework" we cannot help you at all. also if you really need moment then why don't you bundle it into the framework? relying on a third party cdn could result in a possible 404 exception

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.