6

I am trying to run a simple javascript function when my page is completely loaded. For example, this function:

<script type="text/javascript">
function changeSize() {
  var el = document.getElementById("my-id");
  el.style.height = "500px";
  };
</script>

My page has a long-loading (seconds) script retrieved from an external URL that renders the main content in the html body.

I am using Bootstrap where the body section of my base.html is:

<body>

  <div class="container-fluid">
    {% block header %}{% endblock %}

    {% block content %}{% endblock %}

    {% block footer %}{% endblock %}

  </div>

  <!-- jQuery first, then Popper.js, then Bootstrap JS -->
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body>

The content block is loaded via an external html file, which is:

{% extends 'base.html' %}

{% block header %}
{% include 'header.html' %}
{% endblock %}

{% block content %}
  <div class="my-class" id="my-id">
        {{ myapp | safe }}
  </div>
{% endblock %}

{% block footer %}
{% include 'footer.html' %}
{% endblock %}

In the 'my-id' element, myapp is rendered via the long-loading js script that, when finished, renders all the content of the page. The external URL route for myapp is retrieved and defined by a python script using Flask.

I have tried window.onload = changeSize;, <body onload="changeSize();">, and I have checked the timing of all stages of document.readyState.

These all trigger my js function when the html is fully loaded, but before the external script for myapp is complete. How do I detect when all elements and scripts are completely done loading?

EternalObserver
  • 517
  • 7
  • 19
pjw
  • 2,133
  • 3
  • 27
  • 44
  • Where is you script tag? You script should be executed after the external sources. – lumio Mar 07 '19 at 14:48
  • There is no specific script tag in the html for the long-loading script. It is only called via `myapp` in the content block. I can identify the script using the DevTools Network tab as a script that starts with `autoload.js?...`. It continues to load after all other elements are complete. – pjw Mar 07 '19 at 14:56
  • Can you change "`myapp`" or the script it loads? Add a callback feature to notify your page that it is complete. An example is google maps api https://developers.google.com/maps/documentation/javascript/tutorial `` where `initMap` is a function on your page. – freedomn-m Mar 07 '19 at 14:59

2 Answers2

9

I ended up finding a solution using a delay method (adapted from this SO answer).

Put the following in a custom.js file:

function delay() {
    setTimeout(function() {
        changeSize();
    }, 200);
}

if (document.readyState == 'complete') {
    delay();
} else {
    document.onreadystatechange = function () {
        if (document.readyState === "complete") {
            delay();
        }
    }
}

Then load the custom.js in base.html with:

<script type="text/javascript" src="{{ url_for('static', filename='custom.js') }}"></script>

This successfully waits until the long-loading script and related content is fully rendered, then executes the changeSize() function.

pjw
  • 2,133
  • 3
  • 27
  • 44
  • You can do this with a duration of `0` or `setTimeout(function(){ ... },0)` if you're just looking to push the running of the function to the back of the [event loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop). No need to add the extra 200 ms. – tylerwillis Feb 20 '20 at 19:29
3

I'm not sure how the external scripts are loaded. If they loaded using a special library, you need to wait for callback and afterward call your App initialization.

But you can take a look at DOMContentLoaded event. It also could help, If I'm right.

document.addEventListener("DOMContentLoaded", function(event) {
  console.log("DOM fully loaded and parsed");
});
  • 1
    The DOM is full loaded and parsed before the long-running script finishes. – pjw Mar 07 '19 at 15:45
  • The **DOMContentLoaded** event fires when the HTML document has been completely parsed, and all deferred scripts (``` – simUser Jun 20 '23 at 08:39