Получение MathJax для обновления после изменений в модели AngularJS
Я пытаюсь использовать текст двустороннего связывания AngularJS, который включает в себя уравнения стиля латекса. Я хотел бы назвать MathJax для форматирования уравнений, но я не уверен в том, что MathJax вызывается после того, как AngularJS закончит изменение модели. Я думаю, мне нужен обратный вызов. Вот мой 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} \\)';
}
И вот мой HTML:
- Угловая директива динамического шаблона Angular.js
- AngularJs Удалите повторяющиеся элементы в ng-repeat
- Ошибка углового ng-repeat «Дубликаты в ретрансляторе не допускаются».
- Отложить угловое выполнение часов после $ digest (повышение DOM-события)
- Как я могу сохранить новые строки в частичной части AngularJS?
{{Expression}}
Fiddle здесь: http://jsfiddle.net/LukasHalim/UVjTD/1/ . Вы заметите, что на скрипке исходное выражение не удаляется даже после нажатия кнопки обновления дважды – кажется ошибкой или конфликтом.
- Как установить динамическое имя модели в AngularJS?
- ngRoute задает базовый url для всех маршрутов
- Как / когда использовать ng-click для вызова маршрута?
- Как получить данные POST с urlencoded с помощью $ http без jQuery?
- Одностраничное приложение - загрузка js-файла динамически на основе частичного представления
- Использование фильтра даты и времени в формате AngularJS с датой UTC
- Бесконечная петля с привязкой к угловой expressии
- angular.element vs document.getElementById или селектор jQuery со спин (занятым) управлением
Потеряв много дней (и, возможно, недель), сражаясь с MathJax, я слишком хорошо знаком с его различными причудами с обновлением математических выражений на лету. Я совершенно новый для Angular, но это дало мне хороший шанс погрузиться, и я закончил с решением, которое решает мои проблемы – надеюсь, он также решит вашу проблему.
Демо-версия: http://jsfiddle.net/spicyj/YpqVp/
Вместо использования простой интерполяции, которую предоставляет Angular, я создал новую директиву, основанную на ng-bind
называемую mathjax-bind
.
Если expression
представляет собой переменную, содержащую математический код, то вместо \( {{expression}} \)
вы можете написать:
и все будет набираться и обновляться в соответствующее время.
Поддерживающий код для директивы следует:
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("
Простейшее, быстрое и стабильное решение:
$rootScope.$watch(function(){ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); return true; });
Преимущества:
- Простота настройки, просто скопируйте этот код.
- Все на вашей странице набирается.
- Он работает намного быстрее, чем другие решения . Это связано с тем, что он может отображать страницу за один раз. Другие ответы здесь ждут завершения одного элемента, пока они не наберут следующий. Это делает рендеринг рендеринга медленным, если есть, например, несколько директив
mathjax-bind
(как предлагает другой ответ). Этот момент является причиной того, что я искал другой ответ. - Вы все же можете легко исключить элементы, используя опцию «ignoreClass» в настройках mathjax.
Бенчмаркинг: 100 директив mathjax-bind
заняли 63 секунды , в то время как для этого метода потребовалось 1,5 секунды для отображения страницы. Я знаю, что эта функция будет выполняться много, так как она вызывается для каждого цикла дайджеста, однако она заметно не замедляет страницу.
Я создал простую скрипку, расширяющую ответ Бен Алперта. Вот скрипка и плунж .
В частности, если текст имеет только часть его, который должен быть преобразован Mathjax, вы можете использовать это. Для встроенного mathjax вы должны окружить текст символом $, а для отображения блока вы должны окружить блок на $$. (Вы можете использовать любой формат, который вам нравится, если вы создадите соответствующее регулярное выражение)
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; }
Вот директива, которая позволяет использовать двойную курчавую разметку внутри выражения (и не требует установки переменной выражения в области). Он основан на этом сообщении в блоге , за исключением того, что я поддерживаю только MathJax, и я сохраняю скомпилированную DOM, чтобы он обновлял изменения переменных области.
Как сказал Алекс Осборн, лучше всего отделить математику от математики.
Применение:
This is inline math: x^{ {{power}} } , and this is display math:
y^{ {{power}} } .
В fragmentе:
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!
Простым решением является использование $ timeout для размещения MathJax.Hub.Queue(["Typeset", MathJax.Hub])
в очереди событий браузера (см. Запуск директивы после завершения рендеринга DOM ).
Что-то вроде этого:
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]); } });
Взгляните на http://jsfiddle.net/pz5Jc/
В вашем шаблоне:
{{Label}} {{Expression}}
В вашем 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}'); }
Пара пунктов:
Я не слишком хорошо знаком с mathjax, но:
- Выделение метки из выражения позволяет работать с выражением напрямую.
- Вам нужно вручную выбрать элемент DOM, чтобы принудительно обновить выражение. Это не очень «угловой» способ сделать что-то несчастливо, но когда mathjax анализирует выражение (и вставляет его собственные элементы DOM), он толкает эти элементы за пределы угловых привязок.
- Исправить здесь – это выбрать правильный элемент mathjax и вызвать функцию изменения текста для обновления выражения.
Вы можете попробовать с моими изменениями http://jsfiddle.net/bmma8/4/ изменить ввод или нажать кнопку, чтобы обновить ваше выражение.
ЯШ:
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
и html:
You typed: ${}$
Александр
Я действительно думал о другом решении. Когда вы делаете некоторые угловые и математические вы делаете это:
УГОЛЬНЫЙ КОНТРОЛЛЕР
$scope x = 5;
HTML
{{ '$ Multiplication = '+ x + ' * 2 =' + (x*2) + '$'}}
Сформированный результат Math Jax
Умножение = 5 * 2 = 10
Ключ должен включать знаки доллара в скобках в виде текста. Когда Angular делает их, знаки доллара будут отображаться как обычный текст, но когда формат Math Jax вступит в действие, он распознает знаки доллара и совершит волшебство.
Я строю директиву для этого ….
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]); }); } } });
Я немного поработал над решением Рони. Отображение математики должно отображаться в режиме отображения; с
Я добавил атрибут сгенерированного диапазона, чтобы указать это.
Fiddle здесь http://jsfiddle.net/repa/aheujhfq/8/