Getting MathJax to update after changes to Angular

2020-01-27 02:38发布

I am trying to use AngularJS two-way binding text which includes Latex style equations. I would like to call MathJax to format the equations, but I'm not sure of the best way to ensure that MathJax is called after AngularJS finishes changing the model. I think I need a callback. Here is my JavaScript:

var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
   $scope.Update = function() {
       $scope.Expression = 'Evaluate: \\( \\frac{9}{4} \\div \\frac{1}{6} \\)';
       MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
   }
   $scope.Expression = 'Evaluate: \\( \\frac{5}{4} \\div \\frac{1}{6} \\)';

}

And here is my HTML:

<div ng-controller="MyCtrl">
    <button ng-click="Update()">Update</button>
  {{Expression}}
</div>

Fiddle is here: http://jsfiddle.net/LukasHalim/UVjTD/1/. You'll notice that on the fiddle the original expression isn't removed even after you click the update button twice - seems like a bug or conflict.

10条回答
我欲成王,谁敢阻挡
2楼-- · 2020-01-27 03:23

A simple solution is to use $timeout to put MathJax.Hub.Queue(["Typeset", MathJax.Hub]) in the browser event queue (see Run a directive after the DOM has finished rendering).

Something like this:

            var app = angular.module('myApp', []);
            app.controller('myController', function ($scope, $timeout) {
                controller = this;

                $scope.Update = function () {
                    $scope.value = " \\( \\frac{5}{4} \\div \\frac{1}{6} \\)";
                    $timeout(controller.updateMathJax, 0);
                }

                this.updateMathJax = function () {
                    MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
                }
            });
查看更多
甜甜的少女心
3楼-- · 2020-01-27 03:24

I created a simple fiddle expanding on Ben Alpert's answer. Here's the fiddle and plunk.

Specifically If a text has only a part of it to be converted by Mathjax, you can use this. For inline mathjax you must surround the text by $, and for block display you must surround the block by $$. (You can use any format you like if you create the corresponding regex)

app.js

MathJax.Hub.Config({
    skipStartupTypeset: true,
    messageStyle: "none",
    "HTML-CSS": {
        showMathMenu: false
    }
});
MathJax.Hub.Configured();
var myApp = angular.module("myApp", []);
myApp.directive("mathjaxBind", function() {
    return {
        restrict: "A",
        scope:{
            text: "@mathjaxBind"
        },
        controller: ["$scope", "$element", "$attrs", function($scope, $element, $attrs) {
            $scope.$watch('text', function(value) {
                var $script = angular.element("<script type='math/tex'>")
                    .html(value == undefined ? "" : value);
                $element.html("");
                $element.append($script);
                MathJax.Hub.Queue(["Reprocess", MathJax.Hub, $element[0]]);
            });
        }]
    };
});
myApp.directive('dynamic', function ($compile) {
  return {
    restrict: 'A',
    replace: true,
    link: function (scope, ele, attrs) {
      scope.$watch(attrs.dynamic, function(html) {
          html = html.replace(/\$\$([^$]+)\$\$/g, "<span class=\"blue\" mathjax-bind=\"$1\"></span>");
          html = html.replace(/\$([^$]+)\$/g, "<span class=\"red\" mathjax-bind=\"$1\"></span>");
        ele.html(html);
        $compile(ele.contents())(scope);
      });
    }
  };
});
function MyCtrl($scope, $element) {    
    $scope.html = "A coin of is $ \\frac{5}{4} $ thrown $$\\frac{1}{6}$$ dfv";
}

index.html

<!DOCTYPE html>
<html ng-app="myApp">    
  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML&delayStartupUntil=configured&dummy=.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.2.x" src="http://code.angularjs.org/1.2.7/angular.js" data-semver="1.2.7"></script>
    <script src="app.js"></script>
  </head>
  <body>
  <div ng-controller="MyCtrl">
     <input type="text" ng-model="html"/><br/>
     <div dynamic="html"></div>
  </div>
</body>    

style.css

input[type="text"] {
    width: 800px;
}
.red{
    color:red;
    display:inline-block;
}
.blue{
    color:blue;
    display:block;
}
查看更多
forever°为你锁心
4楼-- · 2020-01-27 03:28

Take a look at http://jsfiddle.net/pz5Jc/

In your template:

    {{Label}} <span id="mathElement">{{Expression}}</span>

In your controller:

$scope.Update = function() {
    $scope.Expression = '\\frac{9}{4} \\div \\frac{1}{6}';
    $scope.Label = 'Updated Expression:'
    var math = MathJax.Hub.getAllJax("mathElement")[0];
    math.Text('\\frac{4}{4} \\div \\frac{2}{6}');
}

Couple of points:

I'm not too familiar with mathjax, but:

  • Splitting the label out from the expression allows you to work with the expression directly.
  • You need to manually pick up a DOM element to force a refresh of the expression. This isn't a very 'angular' way to do things unfortunately - but when mathjax parses the expression (and inserts it's own DOM elements), it pushes those elements outside the angular bindings.
  • Fix here is to specifically select the correct mathjax element and call a text change function to update the expression.
查看更多
干净又极端
5楼-- · 2020-01-27 03:30

I Build a directive for this....

FIDDLE: http://jsfiddle.net/8YkUS/1/

HTML

p data-math-exp data-value="math">

JAVASCRIPT

 appFlipped.directive("mathExp", function () {
    return {
        scope: {
            value: "="
        },
        link: function (scope, el) {

            var domEl = el[0];
            scope.$watch("value", function (newValue) {

                //nothing to do here
                if (newValue == null || window.MathJax == null)return;

                //update the dom with the new value and pass the hub for styling the equation
                domEl.innerHTML = '`' + newValue + '`';
                MathJax.Hub.Queue(["Typeset", MathJax.Hub, domEl]);
            });
        }
    }
});
查看更多
登录 后发表回答