I want to serve a little HTML snippet that other pages can include.
The HTML content would look something like this:
<div id="coolIncludable" style="display:none"> <!--be invisible until you are finished initializing -->
<div>Cool stuff here</div>
<div>More cool stuff and so on...</div>
</div>
<script src="http://somehwere/jquery.js"></script>
<script src="http://somewhere/something.js"></script>
<script>
$(function(){$('#coolIncludable').show();});//<- actually contained in a script file, just for illustration
</script>
I'm planning to use the method detailed here: https://www.w3schools.com/howto/howto_html_include.asp to do the actual including. Let's say the page looks something like this:
<html>
<head>
</head>
<body>
<H1>Content before snippet</H1>
<div id="registerWrapper" html-include="http://somehwere/snippet.html">
No content loaded
</div>
<H1>Content after snippet</H1>
<script type="text/javascript" src="http://somehwere/html-include.js"></script>
</body>
</html>
The HTML snippet gets loaded and embedded all right, but the JavaScript that comes with it never gets executed. Is there a way to embed content including scripts that makes sure they are executed?
I don't expect to control the embedding page, so I cannot rely on it having jQuery or anything else loaded. I therefore avoided using jQuery in the embedding function and restricted myself to plain JavaScript. Loading jQuery is one of the things the <script>
tags at the end of the snippets would do.
In retrospect, my mistake is glaringly obvious:
What does the line $(function(){$('#coolIncludable').show();});
do? does it execute $('#coolIncludable').show();
? No it doesn't. It registers a callback to do so that gets triggered by the 'load' event, which already has fired, and won't fire again.
On the other hand, that's really a moot point because the code never even gets executed.
Here's what I learned about dynamic loading of javascript
<div id="snippet">
...
</div>
<!-- neither of these will be executed -->
<script type="text/javascript">alert("stuff");</script>
<script type="text/javascript" src="http://somewhere/script.js"></script>
What does work is dynamic tag generation the way it is described in this article: JavaScript Madness: Dynamic Script Loading
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= 'helper.js';
head.appendChild(script);
//At this point (or soon after) the code in helper.js will be executed
You would do that in your loading script. My loading script looks something like this:
function importJsFiles(){
const scriptFiles = ["http://somewhere/jquery.js",
"http://somewhere/stuff.js",
"http://somewhere/bootstrapSnippet.js"];
for (let i = 0; i< scriptFiles.length; i++){
importJsFile(scriptFiles[i]);
}
}
function includeSnippet(){
//See https://www.w3schools.com/howto/howto_html_include.asp
//We still have to do it without jQuery,
//because at the time this executes the injected jquery.js
//hasn't run and we do not yet have jQuery available
}
importJsFiles();
//At this point, all script tags are created, but the scripts are NOT loaded yet
includeSnippet();
//At this point, the dom is in its final shape
bootstrapSnippet(); //<- This won't work, because the script tags injected by this code won't be evaluated until after this file/function/whatever returns
//bootstrapSnippet.js
function bootstrapSnippet(){
alert("Snippet JS running")
if (window.jQuery) {
alert("JQuery is avaliable"); //<- This will fire, because the new script
// tags are evaluated in order, and we put the
// jquery.js one before the bootstrapSnippet.js one
}
//So now we CAN do this:
$('#coolIncludable').show();
}
bootstrapSnippet();
There are many more interesting ideas and details in this post that I picked the link above from. I hope someday I'll find time to explore them all.