nomen
nomen

Reputation: 3715

MathJax + Knockout.js Subscription

I am using knockout.js to dynamically insert values based on an Ajax call. One of these values, content.front, is utf8 text which can contain MathJax expressions. I am trying to figure out how to get MathJax to render the expressions every time knockout.js updates the div. I can't quite get it to work, and I'm not sure why. Here's the JavaScript:

var ViewModel = function(data) {
  var self = this;
  self = ko.mapping.fromJS(data, {}, self);
  self.content.back.subscribe( function() {
      MathJax.Hub.Queue(["Typeset", MathJax.Hub,"preview-back"]);
  });
}; 

and the Hamlet:

 <div .wrap>
   <div .tab-content>
     <div .tab-pane #preview-back data-bind="text: content.back">

(The html this Hamlet renders is valid html 5...)

As it stands, knockout.js is rendering the text in the appropriate div. And when I change the text, the div changes too. And MathJax seems to be getting triggered -- the little "Typesetting 100%" popup is popping up. But the div isn't getting changed.

Upvotes: 2

Views: 164

Answers (2)

user1392668
user1392668

Reputation: 1

Thank you. This helped me. I updated it for Version 3.0 of MathJax as follows

 ko.bindingHandlers.mathjax = {
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var value = valueAccessor(), allBindings = allBindingsAccessor();

        var valueUnwrapped = ko.unwrap(value);
        $(element).html(valueUnwrapped);   

        MathJax.startup.promise.then(() => {
            MathJax.typesetClear([$(element)[0]]);
            MathJax.typeset([$(element)[0]]);
        });           
    }
};         

This works and typesets the formulas when the observables change but it often fails when I reload the page. The error is

Message: Cannot read properties of undefined (reading 'promise')

I gather this is something to do with sequencing but I have still to resolve it.

Upvotes: 0

nomen
nomen

Reputation: 3715

Okay, so I ended up making a custom binding for knockout. I'm using jquery here, too:

ko.bindingHandlers.mathjax = {
  update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    // This will be called once when the binding is first applied to an element,
    // and again whenever the associated observable changes value.
    // Update the DOM element based on the supplied values here.
    var value = valueAccessor(), allBindings = allBindingsAccessor();

    var valueUnwrapped = ko.unwrap(value);
    // the replace is an artefact of my encoding.  Maybe I will use markdown instead.
    $(element).html(valueUnwrapped.replace(/\n/g, '<br>'));
    MathJax.Hub.Queue(["Typeset",MathJax.Hub,element]);
  }
};

The ViewModel remains the same, and the html template is:

     <div data-bind="mathjax: content.back"></div>

Hopefully this will help somebody else!

Upvotes: 1

Related Questions