New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MathJAX Typeset Queue Error when loading new data into DOM (Cannot read property 'contains' of null) #2071
Comments
You are right that there is an issue if you make the second function call before MathJax has finished typesetting the first one. That is because you are replacing the portion of the DOM where MathJax is typesetting the math, so you have pulled rug out from under MathJax by removing the DOM nodes that it is working on (MathJax does retain pointers to some DOM nodes that is working with, so those will not be freed by the browser, but the parent nodes will, and that is a problem. You are asking about clearing the "typeset" queue, but the queue is about more than just typesetting, so clearing the queue is not the right action (and even if you did, that doesn't stop the current action in the queue). You probably mean to ask about canceling a typesetting action that is already initiated, but you are right, there is no API for that (though it is possible to configure one). But even if there were, you would still be in trouble, because such a cancelation would not be immediate (things are operating asynchronously), so you would still ned to be careful how that was done. The real issue is that you are not synchronizing the changing of the DOM with the typesetting operations. Once you have started a typesetting operation, you should not modify the DOM (at least where the typesetting is occurring) until the typesetting is done. One way to accomplish that is to queue your changes to the DOM as well as the typesetting. That way, the changes will be put off until any previous typesetting is finished. For example,
should resolve the timing issue. Note, however, that your ajax call may complete before the change to the DOM (and subsequent typeset) occurs. So if your ajax call could be made more quickly than MathJax can typeset the changes, this could lead to longer and longer delays between the requested changes and the resulting output on screen. In that case, you might need to be more sophisticated about your handling of the typeset calls. One way would be to keep track of whether a typeset operation is in progress and not queue additional ones until after the typeset is complete; keep track of the last new_math that has been requested (no need to typeset other ones that might have been requested while an earlier one was typeset), and when the typesetting has finished, set the new data and typeset again. You should be able to work out the logic for that. The best solution, however, might be to disable whatever GUI controls allow the user to request new math during the time that MathJax is processing. Something like
where |
Thank you for your detailed reply! I think I will indeed need to disable GUI controls until the typesetting is complete (at least until I can find a better solution). Just for the record, I think this is a pretty common use case:
In our case, the user is navigating the sections of an online math textbook (e.g.: https://www.xyztextbooks.com/ebook/title/college_algebra), and forcing them to wait for all Math to be typeset by MathJAX before they can navigate to another section is not a good solution. We have (in another project) used KaTeX which allows us to pre-render the Math on a server (running NodeJS), and I suppose we could move in that direction (though I'd rather stick with MathJAX). I'm interested in what you mean when you say "there is no API for that (though it is possible to configure one)". I would dearly like to have a method for clearing out pending MathJAX tasks prior to modifying the DOM. |
MathJax v3 (currently in beta) is a complete rewrite of MathJax, and it currently operates synchronously (so no queuing needed). You may find that this is easier to work with in the long rung (though there are still features that are being worked on). It also operates in NodeJS as easily as in a browser, so that could be used for back-end processing. There is also the mathjax-node project that is a server-side implementation of MathJax v2. That is something you could use now if pre-processing by MathJax is a goal for you.
What I had in mind was a means of telling MathJax to cancel the current typeset operation (which is not the same as clearing the queue, but is more likely to be what you actually need). I wrote the following extension for another project, which implements that:
This implements a function You can also keep track of whether MathJax currently is typesetting, and hold off on changes until the cancel goes through. Something like the following (untested) code:
This provides a function The key to making it work is the Although I haven't testing this specific incarnation of the code, I have certainly used this technique in the past, and it should get you on the right path, even if it is not quite right as it stands. |
PS, if you don't want to support all the output formats, you can remove the unwanted blocks from the cancel code above. |
Thanks, again, for taking time to provide a detailed analysis of the situation! I'm currently testing a much simpler solution that seems to be working:
Every time I've used this code, and I monitor MathJAX signals in the browser's javascript console, the events occur in the order I want (i.e., typesetting tasks are all completed and then the callback to re-enable UI controls is run). Here's sample code:
|
Yes, your solution should properly synchronize the changes with MathJax. It is essentially what I had recommended at the end of my first response above; I had suggested pushing the re-enable command on the queue rather than use the Typeset callback, but these are essentially equivalent. So you could do this without the additional closure via
|
Hmm.. Right you are! In my early tests, I could have sworn that the syntax you recommended resulted in things happening in an undesired order, but I just re-ran the tests (observing the signals), and it all works as predicted. Thanks again for all your help! |
No problem. Thanks for reporting your findings. I'm closing this issue, then. |
My website uses a javascript function to load (via AJAX) math markup into the DOM and then render it with MathJAX.
If the function is called a second time (i.e., to load some new math markup into a DOM element):
All works well if MathJAX has finished processing its Typeset queue prior to the second function call.
An error appears if MathJAX has NOT finished processing its Typeset queue prior to the second function call.
MathJax.js?config=TeX-MML-AM_CHTML&latest:19 Uncaught TypeError: Cannot read property 'contains' of null
Once the error occurs, MathJAX is in a bad state and will not function until entirely reloaded (e.g., via a page reload).
It seems like the easiest solution to this problem would be to clear the MathJAX Typeset queue before loading new math via AJAX, but I can find no method in the MathJAX API that clears the Typeset queue.
Here's a stripped-down version of the function (using jQuery syntax) I'm using:
This scenario seems like a common use case, so I hope someone there is a way of avoiding this error.
The text was updated successfully, but these errors were encountered: