Search code examples
javascriptasynchronousmathjax

Rendering MathJax after data is received


I'm receiving data (containing LaTeX code) from an http request and I'd like to render it with MathJax. However, it seems like MathJax starts rendering the code before the data is actually received. To reproduce the bug, I've simulated the HTTP request using a setTimeout of 500ms. Here's an example showing what Im trying to do:

HTML

<html>
<head>
<title>MathJax Test</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script>
     MathJax = {
            tex: {
                inlineMath: [['$', '$'], ['\\(', '\\)']]
            }
        }
</script>
<script type="text/javascript" id="MathJax-script" async
  src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js">
</script>
</head>
<body>
<div id="div1">
<!--  JS fills this div-->

</div>

</body>
</html>

JS

window.addEventListener('DOMContentLoaded', (event) => {

  var para = document.createElement("p");
  var element = document.getElementById("div1");
  
  // Load the element after a delay of 500 ms
  setTimeout(() => {
    para.innerText = '$x=x^2+1$'
    element.appendChild(para)
  }, 500)
})

Here's a JSFiddle with the code above: https://jsfiddle.net/0uo5fhw9/100/

As you can see in the JSFiddle, the LaTeX is not rendering. How do I fix this and tell MathJax to render once all the data has been loaded?


Solution

  • Well if you remove the third script from the html and add it later in the delayed function like so:

        setTimeout(() => {
            var script = document.createElement('script');
            script.src = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js";
            script.type = "text/javascript";
            script.id = "MathJaz-script";
            script.async = true;
            document.getElementsByTagName('head')[0].appendChild(script);
        }, 5000)
    

    It works. This will show the actual text and then, after the delay, convert it into MathJax. If you don't want the text to show before being rendered, you can set it in the timeout function after the script is appended.

    Your HTML:

    <html>
    <head>
    <title>MathJax Test</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
    <script>
         MathJax = {
                tex: {
                    inlineMath: [['$', '$'], ['\\(', '\\)']]
                }
            }
    </script>
    </head>
    <body>
    <div id="div1">
    
    </div>
    
    </body>
    </html>
    

    Your JS:

    window.addEventListener('DOMContentLoaded', (event) => {
    
      var para = document.createElement("p");
    
      var element = document.getElementById("div1");
        para.innerText = '$x=x^2+1$'
        element.appendChild(para)
      
      setTimeout(() => {
      var script = document.createElement('script');
        script.src = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js";
      script.type = "text/javascript";
      script.id = "MathJaz-script";
      script.async = true;
        document.getElementsByTagName('head')[0].appendChild(script);
      }, 5000)
    })