laravellaravel-livewiremathjaxlivewire-3

Using MathJax in a Livewire component - formatter doesn't work on subsequent livewire requests


Overview: I am trying to use MathJax in my livewire component to format math problems. It works fine until a livewire request is made.

What I have done:

I have added the following to my layout file:

   <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>

My Livewire component:

class ShowMathProblemPage extends Component
{
    public string $problem = '$$4^2 + 4/6$$';

    public function generateNewProblem()
    {
        $this->problem = '$$5/534^56$$';
    }

}

Livewire blade:

<div>
    {{ $problem }}
    <button wire:click="generateNewProblem">
        New Problem
     </button>
</div>

The issue: It works on initial load - but as soon as the livewire call is made to generateNewProblem (or anything else) the formatter is not reapplied.

I have tried using the following (and variation) to trigger the formatter to run again with no dice:

<script>
    document.addEventListener("DOMContentLoaded", () => {
        Livewire.on('run-formatter', () => {
            MathJax.typesetPromise().then(() => {
                MathJax.typesetPromise();
            }).catch((err) => console.log(err.message));
        });

    });
</script>

Solution

  • This is a possible solution:

    public function generateNewProblem()
    {
        $this->problem = '$$5/534^56$$';
        $this->dispatch('run-formatter');
    }
    
    <div @run-formatter.window="$nextTick(() => MathJax.typeset())">
    
        {{ $problem }}
    
        <button wire:click="generateNewProblem">
            New Problem
        </button>
    
    </div>
    

    The event is captured by the container of the element to be formatted, using $nextTick() the formatting is invoked after the dom has been updated


    If you want to maintain global level management, you can modify your code like this:

    <script>
        document.addEventListener("alpine:init", () => {  // "livewire:init" works too 
    
            Livewire.on('run-formatter', () => {
                Alpine.nextTick (() => MathJax.typeset());
            });
        });
    </script>