knockout.jsmathjax

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.


Solution

  • 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!