Reputation: 365
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 500
ms. 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?
Upvotes: 0
Views: 837
Reputation: 12260
MathJax typesets the contents of the page when the DOMContentLoaded
event occurs, so if you change the page after that, as in your example, you need to ask MathJax to typeset the page again. See the documentation for details, but you can do that with the MathJax.typeset()
or MathJax.typesetPromise()
methods.
Here is your example, modified to do this:
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);
if (MathJax) MathJax.typesetPromise();
}, 500);
})
<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>
Upvotes: 2
Reputation: 735
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)
})
Upvotes: 0