0

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.

TylerH
  • 20,799
  • 66
  • 75
  • 101
drdeath
  • 81
  • 1
  • 11

2 Answers2

0

Since you are using jQuery you can use it's built in load() method to do what you want

Something like:

HTML

<div class="include" data-include="page2.html"></div>

JS

$('.include').each(function(){
     const $el = $(this), url = $el.data('include');
     $el.load(url)
});

Then make sure the script tag for the new content is below that content.

Simple working demo

charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • I probably should have emphasized that. I don't expect to have control over the embedding web page, so that might not have jQuery loaded. I therefore carefully avoided using any specific jQuery code and used plain javascript in the loading routine. – drdeath Jul 21 '21 at 13:41
  • But your solution is very interesting anyway, and a good point if you *can* rely on jQuery being available. – drdeath Jul 21 '21 at 13:48
  • OK well you tagged this with jQuery and did use jQuery code in question – charlietfl Jul 21 '21 at 18:03
  • I am kinda new to this. And I *am* using jQuery, only my question is more about how to load it than how to use it. – drdeath Jul 22 '21 at 12:51
0

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

Injecting script tags directly does not work

  • script tags injected by setting element.innerHtml do not get executed
<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>

Creating script tags dynamically does work

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.

drdeath
  • 81
  • 1
  • 11