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.
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-bind
mathjax-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]]);
});
}]
};
});
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.
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;
}
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>
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]);
}
});
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.
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
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.
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]);
});
}
}
});
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/