Mise à jour de MathJax après les modifications du modèle AngularJS

j'essaie D'utiliser AngularJS texte de liaison bidirectionnel qui comprend des équations de style Latex. Je voudrais appeler MathJax pour formater les équations, mais je ne suis pas sûr de la meilleure façon de s'assurer que MathJax est appelé après AngularJS finis de changer le modèle. Je pense que j'ai besoin d'un rappel. Voici mon code 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} )';

}

et voici mon HTML:

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

Violon est ici: http://jsfiddle.net/LukasHalim/UVjTD/1/. Vous remarquerez que sur le violon l'expression originale ne soit pas supprimée même après avoir cliqué deux fois sur le bouton de mise à jour - cela ressemble à un bug ou à un conflit.

26
demandé sur Lukas Halim 2013-04-18 19:31:52

10 réponses

ayant perdu de nombreux jours (et peut-être des semaines) à combattre MathJax, je suis trop familier avec ses différentes bizarreries avec la mise à jour des expressions mathématiques à la volée. Je suis tout nouveau à L'Angular mais cela m'a donné une bonne chance de plonger et j'ai fini avec une solution qui résout mes problèmes -- j'espère que cela résoudra les vôtres aussi bien.

démonstration en Direct: http://jsfiddle.net/spicyj/YpqVp/


au lieu d'utiliser l'interpolation simple que Angular provides, j'ai créé une nouvelle directive basée sur ng-bindmathjax-bind.

Si expression est une variable contenant du code mathématique, alors au lieu de \( {{expression}} \) vous pouvez écrire:

<span mathjax-bind="expression"></span>

et tout sera composé et mis à jour en temps opportun.

le code de support de la directive est le suivant:

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("<script type='math/tex'>")
                    .html(texExpression ? texExpression :  "");
                $element.html("");
                $element.append(texScript);
                MathJax.Hub.Queue(["Reprocess", MathJax.Hub, $element[0]]);
            });
        }]
    };
});
36
répondu Sophie Alpert 2014-08-07 21:01:44

solution la plus simple, la plus rapide et la plus stable:

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

les Avantages:

  • facile à configurer, il suffit de copier ce code.
  • tout sur votre page est composé.
  • il rend beaucoup plus rapide que les autres solutions. C'est parce qu'il peut afficher la page en une seule fois. Les autres réponses ici attendent qu'un élément se termine, jusqu'à ce qu'ils tapent le suivant. Qui rend veeeery lent si là sont, par exemple, plusieurs mathjax-bind directives (comme une autre réponse le suggère). Ce point est la raison pour laquelle je cherchais une réponse différente.
  • vous pouvez encore facilement exclure des éléments en utilisant l'option "ignoreClass" dans vos paramètres mathjax.

Benchmarking: 100 mathjax-bind les directives pris 63 secondes, alors qu'avec cette méthode, il a pris 1,5 seconde pour rendre la page. Je sais que cette fonction sera souvent exécutée puisqu'elle est appelée chaque cycle de digest, cependant, il ne ralentit pas sensiblement la page.

11
répondu 2016-11-14 13:41:40

j'ai créé un violon simple développant la réponse de Ben Alpert. Voici le tripoter et plunk.

spécifiquement si un texte n'en a qu'une partie à convertir par Mathjax, vous pouvez l'utiliser. Pour mathjax inline vous devez entourer le texte par $, et pour l'affichage de bloc vous devez entourer le bloc par$$$. (Vous pouvez utiliser n'importe quel format que vous souhaitez si vous créez le correspondant 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=\"\"></span>");
          html = html.replace(/$([^$]+)$/g, "<span class=\"red\" mathjax-bind=\"\"></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;
}
7
répondu Roney Island 2014-10-11 16:26:35

Voici une directive qui vous permet d'utiliser un double marqueur curly à l'intérieur de l'expression (et qui ne nécessite pas de définir une variable d'expression sur le scope). Il est basé sur ce post, sauf que je supporte seulement MathJax, et je sauve le DOM compilé, de sorte qu'il met à jour les modifications des variables de scope.

comme L'a dit Alex Osborn, il est préférable de séparer les non-mathématiques des mathématiques.

Utilisation:

<p>This is inline math: <latex>x^{ {{power}} }</latex>, 
and this is display math: <div latex> y^{ {{power}} } .</div></p>

Dans un extrait:

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]);
        });
      }
    }
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>

<div ng-app="app" ng-controller="ctrl">
  <p>Power:
    <input ng-model="power" />
  </p>
  <p>This is the inline latex,
    <latex>x^{ {{power}} }</latex>, followed by some display mode latex
    <div latex>y^{ {{power}} } = {{power}}.</div>And that's it!
  </p>
</div>
2
répondu jladan 2015-04-28 01:29:32
MathJax.Hub.Queue(["Typeset", MathJax.Hub]) dans la file d'attente des événements du navigateur (voir exécutez une directive après que le DOM a terminé le rendu).

quelque Chose comme ceci:

            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]);
                }
            });
2
répondu Pedro Mestre Silva 2015-05-01 13:41:40

regardez http://jsfiddle.net/pz5Jc/

dans votre modèle:

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

Dans votre contrôleur:

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

Quelques points:

je ne suis pas trop familier avec mathjax, mais:

  • séparer l'étiquette de l'expression vous permet de travailler directement avec l'expression.
  • vous devez saisir manuellement un élément DOM pour forcer un rafraîchissement de l'expression. Ce n'est pas une façon très "angulaire" de faire les choses malheureusement - mais quand mathjax parse l'expression (et insère ses propres éléments DOM), il pousse ces éléments à l'extérieur des fixations angulaires.
  • corriger ici est de sélectionner spécifiquement l'élément mathjax correct et d'appeler une fonction de modification de texte pour mettre à jour l'expression.
1
répondu Alex Osborn 2013-04-18 21:23:00

Vous pouvez essayer avec mes modifications http://jsfiddle.net/bmma8/4/ modifier input ou cliquer sur le bouton mettra à jour votre expression.

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

et le code html:

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

         <input ng-model="Expression" ng-change="Update()">
         <div id="MathOutput">
         You typed: ${}$
         </div>
 </div>

Alexandre

1
répondu heralight 2013-04-18 21:54:04

j'ai en fait pensé à une autre solution. Quand vous rendez un peu anguleux et maths vous faites ceci:

RÉGULATEUR ANGULAIRE

$scope x = 5;

HTML

<h3> {{ '$ Multiplication = '+ x + ' * 2 =' + (x*2) + '$'}} </h3>

Formaté Mathématiques Jax résultat

Multiplication = 5 * 2 = 10

La clé est d'inclure le dollar signalisation à l'intérieur des parenthèses, comme texte. Quand Angular les rend, les signes dollar apparaîtront en texte simple, mais quand le format Math Jax entre en action il sera reconnais les signes du dollar et fais la magie.

0
répondu Avi 2014-05-27 17:20:55

j'ai construit une directive pour ça....

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

HTML

p données-mathématiques-exp données-valeur="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]);
            });
        }
    }
});
0
répondu Jose Ch. 2014-07-03 05:38:47

J'ai bricolé un peu plus sur la solution de Roney. Le calcul d'affichage doit être affiché en mode Affichage; avec

<script type="math/tex; mode=display">

j'ai ajouté un attribut généré span indiquer que.

Violon est ici http://jsfiddle.net/repa/aheujhfq/8/

0
répondu user3021380 2015-02-12 21:13:56