Conseguir MathJax para actualizar después de los cambios en el modelo AngularJS

Estoy tratando de usar el texto de enlace bidireccional AngularJS que incluye ecuaciones de estilo Latex. Me gustaría llamar a MathJax para formatear las ecuaciones, pero no estoy seguro de la mejor manera de asegurar que se invoque MathJax después de que AngularJS termine de cambiar el modelo. Creo que necesito una callback. Aquí está mi 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} \\)'; 

}

Y aquí está mi HTML:

 
{{Expression}}

Fiddle está aquí: http://jsfiddle.net/LukasHalim/UVjTD/1/ . Notarás que en el violín la expresión original no se elimina incluso después de hacer clic en el botón de actualización dos veces, parece un error o conflicto.

Después de haber perdido muchos días (y tal vez semanas) luchando contra MathJax, estoy muy familiarizado con sus diversas peculiaridades con la actualización de las expresiones matemáticas sobre la marcha. Soy nuevo en Angular, pero esto me dio una buena oportunidad para sumergirme y terminé con una solución que soluciona mis problemas. Espero que también resuelva la tuya.

Demostración en vivo: http://jsfiddle.net/spicyj/YpqVp/


En lugar de utilizar la interpolación simple que proporciona Angular, creé una nueva directiva basada en ng-bind llamada mathjax-bind .

Si la expression es una variable que contiene código matemático, en lugar de \( {{expression}} \) puede escribir:

  

y todo se comstackrá y actualizará en los momentos apropiados.

El código de soporte para la directiva sigue:

 myApp.directive("mathjaxBind", function() { return { restrict: "A", controller: ["$scope", "$element", "$attrs", function($scope, $element, $attrs) { $scope.$watch($attrs.mathjaxBind, function(texExpression) { var texScript = angular.element(" 

La solución más simple, más rápida y más estable:

 $rootScope.$watch(function(){ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); return true; }); 

Ventajas:

  • Fácil de configurar, solo copie este código.
  • Todo en tu página está compuesto por tipografía.
  • Se procesa mucho más rápido que las otras soluciones . Esto se debe a que puede mostrar la página de una vez. Otras respuestas aquí esperan a que termine un elemento, hasta que escriban el siguiente. Eso hace que el renderizado sea lento si hay, por ejemplo, varias directivas mathjax-bind (como sugiere otra respuesta). Este es el motivo por el que estaba buscando una respuesta diferente.
  • Todavía puede excluir elementos fácilmente usando la opción “ignorarClase” en su configuración de mathjax.

Benchmarking: 100 directivas mathjax-bind tomaron 63 segundos , mientras que con este método se tardó 1,5 segundos en renderizar la página. Sé que esta función se ejecutará mucho ya que se utiliza en cada ciclo de resumen, sin embargo, no ralentiza notablemente la página.

Creé un violín simple expandiendo la respuesta de Ben Alpert. Aquí está el violín y el plunk .

Específicamente Si un texto tiene solo una parte para convertirlo Mathjax, puede usarlo. Para mathjax en línea debe rodear el texto por $, y para mostrar en bloque debe rodear el bloque por $$. (Puede usar cualquier formato que desee si crea la expresión regular correspondiente)

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(" 

index.html

     AngularJS Plunker        

style.css

 input[type="text"] { width: 800px; } .red{ color:red; display:inline-block; } .blue{ color:blue; display:block; } 

Aquí hay una directiva que le permite usar marcas dobles rizadas dentro de la expresión (y no requiere establecer una variable de expresión en el scope). Está basado en esta publicación de blog , excepto que solo soporto MathJax, y guardo el DOM comstackdo, para que se actualice en los cambios a las variables de ámbito.

Como dijo Alex Osborn, lo mejor es separar las matemáticas de las no matemáticas.

Uso:

 

This is inline math: x^{ {{power}} }, and this is display math:

y^{ {{power}} } .

En un fragmento:

 angular.module('app', []) .controller('ctrl', function($scope) { $scope.power = "\\sin(x^2)"; }) .directive('latex', function() { return { restrict: 'AE', link: function(scope, element) { var newDom = element.clone(); element.replaceWith(newDom); var pre = "\\(", post = "\\)"; if (element[0].tagName === 'DIV') { pre = "\\["; post = "\\]"; } scope.$watch(function() { return element.html(); }, function() { console.log(element); newDom.html(pre + element.html() + post); MathJax.Hub.Typeset(newDom[0]); }); } } }); 
   

Power:

This is the inline latex, x^{ {{power}} }, followed by some display mode latex

y^{ {{power}} } = {{power}}.
And that's it!

Una solución simple es usar $ timeout para poner MathJax.Hub.Queue(["Typeset", MathJax.Hub]) en la cola de eventos del navegador (consulte Ejecutar una directiva una vez que el DOM haya finalizado la representación ).

Algo como esto:

  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]); } }); 

Eche un vistazo a http://jsfiddle.net/pz5Jc/

En tu plantilla:

  {{Label}} {{Expression}} 

En tu controlador:

 $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}'); } 

Un par de puntos:

No estoy muy familiarizado con mathjax, pero:

  • Dividir la etiqueta de la expresión le permite trabajar con la expresión directamente.
  • Necesita seleccionar manualmente un elemento DOM para forzar una actualización de la expresión. Esta no es una forma muy ‘angular’ de hacer las cosas desafortunadamente, pero cuando mathjax analiza la expresión (e inserta sus propios elementos DOM), empuja esos elementos fuera de los enlaces angulares.
  • La solución aquí es seleccionar específicamente el elemento mathjax correcto y llamar a una función de cambio de texto para actualizar la expresión.

Puedes probar con mis modificaciones http://jsfiddle.net/bmma8/4/ modificar la entrada o hacer clic en el botón para actualizar tu expresión.

js:

 MathJax.Hub.Config({ extensions: ["tex2jax.js"], jax: ["input/TeX","output/HTML-CSS"], tex2jax: {inlineMath: [["$","$"],["\\(","\\)"]]} }); var myApp = angular.module('myApp',[]); function MyCtrl($scope, $log) { var QUEUE = MathJax.Hub.queue; // shorthand for the queue $scope.Update = function() { QUEUE.Push(["Text",MathJax.Hub.getAllJax("MathOutput")[0],"\\displaystyle{"+ $scope.Expression+"}"]); //$scope.Expression = 'Updated Expression: \\( \\frac{9}{4} \\div \\frac{1}{6} \\)'; //MathJax.Hub.Queue(["Typeset", MathJax.Hub]); } $scope.Expression = 'Original Expression: \\( \\frac{5}{4} \\div \\fra 

y html:

  
You typed: ${}$

Alexandre

De hecho, pensé en otra solución. Cuando renderiza algunas operaciones angulares y matemáticas, hace esto:

CONTROLADOR ANGULAR

 $scope x = 5; 

HTML

 

{{ '$ Multiplication = '+ x + ' * 2 =' + (x*2) + '$'}}

Resultado matemático Formateado Jax

Multiplicación = 5 * 2 = 10

La clave es incluir los signos de dólar dentro de los corchetes como texto. Cuando Angular los renderiza, los signos de dólar aparecerán como texto sin formato, pero cuando el formato Math Jax entre en acción, reconocerá los signos de dólar y hará la magia.

Construyo una directiva para esto …

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]); }); } } }); 

Jugué un poco más en la solución de Roney. La pantalla matemática debe mostrarse en modo de visualización; con

  

Agregué un atributo al tramo generado para indicar eso.

Fiddle está aquí http://jsfiddle.net/repa/aheujhfq/8/