Angular 2.0 and Mathjax not working well - javascript

I pieced together a semi working edition of mathjax with angular 2.0, but it is breaking in a manner I can not quite grasp. I have added a plunkr below to clearly demonstrate the situation.
In my code (not the plunkr) this is my relevant html:
<textarea
#editorArea
ngDefaultControl
spellcheck="false"
class="editor"
[(ngModel)]='assignment.content.text'
(keyup)="updateResult()"
[ngStyle]="{'height' : formatDimension(editorDimensions.height), 'padding' : formatDimension(editorDimensions.padding)}
"></textarea>
<div class="result" #result>{{ editorArea.value }}</div>
and this is the relevant update function triggered from the HTML:
#ViewChild('result') result : ElementRef;
updateResult() {
MathJax.Hub.Queue(["Typeset", MathJax.Hub, this.result.nativeElement]);
}
Finally this is my mathJax configuration:
<script type="text/x-mathjax-config">
MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}});
</script>
http://plnkr.co/edit/lEJZZaxKUYxFGdLtWW7Z?p=preview

It seems like the main question here is how to repeatedly render the contents of the <textarea> into a separate area of the page using MathJax. This is covered in a simple case in the Modifying Math on the Page documentation.
Basically you have two options:
Option 1
Keep ahold of the rendered math element and then use the Text function to re-render with a new math string (Note: this requires that the whole textarea is one big math string, not normal text with math strings interspersed) Plunker:
HTML :
<div id="result">$ $ <!-- empty mathstring as placeholder -->
hello-mathjax.ts (portion):
ngOnInit() {
var self = this;
// callback function saves the rendered element, so it can
// be re-rendered on update with the "Text" function.
MathJax.Hub.Queue(
["Typeset",MathJax.Hub,"result"],
function () {self.resultElement = MathJax.Hub.getAllJax("result")[0];
self.updateResult();
}
);
}
updateResult () {
// re-render the same element with the value from the textarea
MathJax.Hub.Queue(["Text",this.resultElement,this.inputValue]);
}
updateResult () {
MathJax.Hub.Queue(["Text",this.resultElement,this.inputValue]);
}
Option 2
Wipe out the renderd div every time and completely re-render the contents of the textarea. (This is the way to go if the textarea will contain a mix of mathstrings and regular text) Plunker:
HTML:
<div id="result"></div> <!-- No placeholder math string needed -->
hello-mathjax.ts (portion):
ngOnInit() {
var self = this;
MathJax.Hub.Queue(
["Typeset",MathJax.Hub,"result"],
function () {
self.updateResult();
}
);
}
updateResult () {
var resultDiv = document.getElementById("result");
// Replace the rendered content entirely
// with the bare text from the textarea.
resultDiv.innerHTML = this.inputValue;
// Rerender the entire resultDiv
MathJax.Hub.Queue(["Typeset",MathJax.Hub,"result"]);
}
This plunker demonstrates rendering a <textarea> that contains a mix of non-math and math statements (e.g. test test $\frac 12$)
This Plunker demonstrates rendering a <textarea> that should be interpreted entirely as math statements (e.g. \frac {11}2)

Related

If Knockout wraps a bounded function expression in a computed, why it doesn't always create a depndency?

This is a follow-up question to this one:
As explained in the above-linked answer:
When you provide an expression for a binding value rather than just a
reference to an observable, KO effectively wraps that expression in a
computed when applying the bindings.
Thus, I expected that when providing the changeCity as a binding expression (it is a function and not an observable), then changing the value on the input box would fire the changeCity function.
However, as you can see on the first snippet, it doesn't (Nor when binding it as changeCity()), but If changeCity is declared as a ko.computed, it does fire - see the second snippet.
Does it mean that a bounded function and a bounded computed are not completely the same with regard to dependency tracking?
First snippet - bounded function:
var handlerVM = function () {
var self = this;
self.city = ko.observable("London");
self.country = ko.observable("England");
self.changeCity = function () {
if (self.country() == "England") {
self.city("London");
} else {
self.city("NYC");
}
}
}
ko.applyBindings(new handlerVM());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<h3 data-bind="text: city"> </h1>
<span data-bind="text: 'change the country, get out of focus, and nothing will happen...'"></span>
<br/>
<input data-bind="value: country" />
Second snippet - bounded computed:
var handlerVM = function () {
var self = this;
self.city = ko.observable("London");
self.country = ko.observable("England");
self.changeCity = ko.computed(function () {
if (self.country() == "England") {
self.city("London");
} else {
self.city("NYC")
}
});
}
ko.applyBindings(new handlerVM());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<h3 data-bind="text: city"> </h1>
<span data-bind="text: 'change the country, get out of focus, and behold:'"> </span>
<br/>
<input data-bind="value: country" />
I take it that you're not just trying to solve a practical problem, but that you're mostly interested in the "theoretical difference" between passing a computed or a plain function to a binding. I'll try to explain the differences/similarities.
Let's start with an example
const someObs = ko.observable(10);
const someFn = () => someObs() + 1;
const someComp = ko.computed(someFn);
const dec = () => someObs(someObs() - 1);
ko.applyBindings({ someObs, someFn, someComp, dec });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div>Obs. value: <span data-bind="text: someObs"></span></div>
<div>Computed created in binding: <span data-bind="text: someFn()"></span></div>
<div>Computed created in vm: <span data-bind="text: someComp"></span></div>
<button data-bind="click: dec">-1</button>
The example above shows that both someFn and someComp do the same thing. By referencing someFn() in a binding handler's value, you've essentially created a computed with a dependency to someObs.
Why this doesn't work in your first example
You never referenced your changeCity method in any knockout related code, which means there'll never be the chance to create a dependency. Of course, you can force one, but it's kind of weird:
var handlerVM = function () {
var self = this;
self.city = ko.observable("London");
self.country = ko.observable("England");
self.changeCity = function () {
if (self.country() == "England") {
self.city("London");
} else {
self.city("NYC");
}
}
}
ko.applyBindings(new handlerVM());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<h3 data-bind="text: city"> </h1>
<span data-bind="html: 'change the country, get out of focus, and <strike>nothing</strike> <strong>something</strong> will happen...'"></span>
<br/>
<input data-bind="value: (changeCity(), country)" />
Why a regular computed does work
In your second example, you use a ko.computed. Upon instantiating a ko.computed, the passed function is evaluated once (immediately) and dependencies to all used observables are created.
If you were to change the ko.computed to a ko.pureComputed, you'll see your second example will also stop working. A pureComputed only evaluates once its return value is actually used and won't create dependencies until then.
The internals
Knockout wraps your binding's value in a function as a string. You can read more about this in an answer I wrote earlier.
We also know that any observable that is called inside a binding-handler's init method, creates a dependency that calls the binding's update method when a change happens.
So, in the example I gave, this is what happens:
The text binding is parsed
The function function() { return someFn(); } is passed as a value accessor to the text binding's init method.
The value accessor is called to initialize the text field
someObs is asked for its value and a dependency is created
The correct value is rendered to the DOM
Then, upon pressing the button and changing someObs:
someObs is changed, triggering the text binding's update method
The update method calls the valueAccessor, re-evaluating someObs and correctly updating its text.
Practical advice
To wrap up, some practical advice:
Use a ko.pureComputed when you create a new value out of one or more observable values. (your example)
self.city = ko.pureComputed(
() => self.country() === "england"
? "london"
: "nyc"
);
Use a subscribe if you want to create side effects based on an observable value changing. E.g.: a console.log of a new value or a reset of a timer.
Use a ko.computed when you want to create side effects based on a change in any of several observables.
the expected behavior in both snippets is that once the text in the input box is changed (and the focus is out), changeCity is fired (Happens on the 2nd, not on the 1st).
Ahhh, now I understand. You are describing what a subscription does.
First off, rid your mind of DOM events. The <input> field does not exist. All there is is your viewmodel. (*)
With this mind-set it's clear what to do: React to changes in your country property, via .subscribe(). The following does what you have in mind.
var handlerVM = function () {
var self = this;
self.city = ko.observable("London");
self.country = ko.observable("England");
self.country.subscribe(function (newValue) {
switch (newValue.toLowerCase()) {
case "england":
self.city("London");
break;
case "usa":
self.city("NYC");
break;
default:
self.city("(unknown)");
}
});
}
ko.applyBindings(new handlerVM());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<h3 data-bind="text: city"></h3>
<input data-bind="value: country" />
(*) Of course the <input> field still exists. But it helps to imagine the view (your HTML) as 100% dependent on your viewmodel. Knockout does all the viewmodel-view interaction for you. It takes care of displaying changes in the viewmodel data, and it takes care of feeding back user interactions into your viewmodel. All you should pay attention to is changes in your viewmodel.
Whenever you feel that you need to listen to a basic DOM event like "click", chances are that you are doing something wrong, i.e. chances are you are missing an observable, or a custom binding.

Using Javascript loop to create multiple HTML elements

I would like to use a javascript loop to create multiple HTML wrapper elements and insert JSON response API data into some of the elements (image, title, url, etc...).
Is this something I need to go line-by-line with?
<a class="scoreboard-video-outer-link" href="">
<div class="scoreboard-video--wrapper">
<div class="scoreboard-video--thumbnail">
<img src="http://via.placeholder.com/350x150">
</div>
<div class="scoreboard-video--info">
<div class="scoreboard-video--title">Pelicans # Bulls Postgame: E'Twaun Moore 10-8-17</div>
</div>
</div>
</a>
What I am trying:
var link = document.createElement('a');
document.getElementsByTagName("a")[0].setAttribute("class", "scoreboard-video-outer-link");
document.getElementsByTagName("a")[0].setAttribute("url", "google.com");
mainWrapper.appendChild(link);
var videoWrapper= document.createElement('div');
document.getElementsByTagName("div")[0].setAttribute("class", "scoreboard-video-outer-link");
link.appendChild(videoWrapper);
var videoThumbnailWrapper = document.createElement('div');
document.getElementsByTagName("div")[0].setAttribute("class", "scoreboard-video--thumbnail");
videoWrapper.appendChild(videoThumbnailWrapper);
var videoImage = document.createElement('img');
document.getElementsByTagName("img")[0].setAttribute("src", "url-of-image-from-api");
videoThumbnailWrapper.appendChild(videoImage);
Then I basically repeat that process for all nested HTML elements.
Create A-tag
Create class and href attributes for A-tag
Append class name and url to attributes
Append A-tag to main wrapper
Create DIV
Create class attributes for DIV
Append DIV to newly appended A-tag
I'd greatly appreciate it if you could enlighten me on the best way to do what I'm trying to explain here? Seems like it would get very messy.
Here's my answer. It's notated. In order to see the effects in the snippet you'll have to go into your developers console to either inspect the wrapper element or look at your developers console log.
We basically create some helper methods to easily create elements and append them to the DOM - it's really not as hard as it seems. This should also leave you in an easy place to append JSON retrieved Objects as properties to your elements!
Here's a Basic Version to give you the gist of what's happening and how to use it
//create element function
function create(tagName, props) {
return Object.assign(document.createElement(tagName), (props || {}));
}
//append child function
function ac(p, c) {
if (c) p.appendChild(c);
return p;
}
//example:
//get wrapper div
let mainWrapper = document.getElementById("mainWrapper");
//create link and div
let link = create("a", { href:"google.com" });
let div = create("div", { id: "myDiv" });
//add link as a child to div, add the result to mainWrapper
ac(mainWrapper, ac(div, link));
//create element function
function create(tagName, props) {
return Object.assign(document.createElement(tagName), (props || {}));
}
//append child function
function ac(p, c) {
if (c) p.appendChild(c);
return p;
}
//example:
//get wrapper div
let mainWrapper = document.getElementById("mainWrapper");
//create link and div
let link = create("a", { href:"google.com", textContent: "this text is a Link in the div" });
let div = create("div", { id: "myDiv", textContent: "this text is in the div! " });
//add link as a child to div, add the result to mainWrapper
ac(mainWrapper, ac(div, link));
div {
border: 3px solid black;
padding: 5px;
}
<div id="mainWrapper"></div>
Here is how to do specifically what you asked with more thoroughly notated code.
//get main wrapper
let mainWrapper = document.getElementById("mainWrapper");
//make a function to easily create elements
//function takes a tagName and an optional object for property values
//using Object.assign we can make tailored elements quickly.
function create(tagName, props) {
return Object.assign(document.createElement(tagName), (props || {}));
}
//document.appendChild is great except
//it doesn't offer easy stackability
//The reason for this is that it always returns the appended child element
//we create a function that appends from Parent to Child
//and returns the compiled element(The Parent).
//Since we are ALWAYS returning the parent(regardles of if the child is specified)
//we can recursively call this function to great effect
//(you'll see this further down)
function ac(p, c) {
if (c) p.appendChild(c);
return p;
}
//these are the elements you wanted to append
//notice how easy it is to make them!
//FYI when adding classes directly to an HTMLElement
//the property to assign a value to is className -- NOT class
//this is a common mistake, so no big deal!
var link = create("a", {
className: "scoreboard-video-outer-link",
url: "google.com"
});
var videoWrapper = create("div", {
className: "scoreboard-video-outer-link"
});
var videoThumbnailWrapper = create("div", {
className: "scoreboard-video--thumbnail"
});
var videoImage = create("img", {
src: "url-of-image-from-api"
});
//here's where the recursion comes in:
ac(mainWrapper, ac(link, ac(videoWrapper, ac(videoThumbnailWrapper, videoImage))));
//keep in mind that it might be easiest to read the ac functions backwards
//the logic is this:
//Append videoImage to videoThumbnailWrapper
//Append (videoImage+videoThumbnailWrapper) to videoWrapper
//Append (videoWrapper+videoImage+videoThumbnailWrapper) to link
//Append (link+videoWrapper+videoImage+videoThumbnailWrapper) to mainWrapper
let mainWrapper = document.getElementById('mainWrapper');
function create(tagName, props) {
return Object.assign(document.createElement(tagName), (props || {}));
}
function ac(p, c) {
if (c) p.appendChild(c);
return p;
}
var link = create("a", {
className: "scoreboard-video-outer-link",
url: "google.com"
});
var videoWrapper = create("div", {
className: "scoreboard-video-outer-link"
});
var videoThumbnailWrapper = create("div", {
className: "scoreboard-video--thumbnail"
});
var videoImage = create("img", {
src: "url-of-image-from-api"
});
ac(mainWrapper, ac(link, ac(videoWrapper, ac(videoThumbnailWrapper, videoImage))));
//pretty fancy.
//This is just to show the output in the log,
//feel free to just open up the developer console and look at the mainWrapper element.
console.dir(mainWrapper);
<div id="mainWrapper"></div>
Short version
Markup.js's loops.
Long version
You will find many solutions that work for this problem. But that may not be the point. The point is: is it right? And you may using the wrong tool for the problem.
I've worked with code that did similar things. I did not write it, but I had to work with it. You'll find that code like that quickly becomes very difficult to manage. You may think: "Oh, but I know what it's supposed to do. Once it's done, I won't change it."
Code falls into two categories:
Code you stop using and you therefore don't need to change.
Code you keep using and therefore that you will need to change.
So, "does it work?" is not the right question. There are many questions, but some of them are: "Will I be able to maintain this? Is it easy to read? If I change one part, does it only change the part I need to change or does it also change something else I don't mean to change?"
What I'm getting at here is that you should use a templating library. There are many for JavaScript.
In general, you should use a whole JavaScript application framework. There are three main ones nowadays:
ReactJS
Vue.js
Angular 2
For the sake of honesty, note I don't follow my own advice and still use Angular. (The original, not Angular 2.) But this is a steep learning curve. There are a lot of libraries that also include templating abilities.
But you've obviously got a whole project already set up and you want to just plug in a template into existing JavaScript code. You probably want a template language that does its thing and stays out of the way. When I started, I wanted that too. I used Markup.js . It's small, it's simple and it does what you want in this post.
https://github.com/adammark/Markup.js/
It's a first step. I think its loops feature are what you need. Start with that and work your way to a full framework in time.
Take a look at this - [underscore._template]
It is very tiny, and useful in this situation.
(https://www.npmjs.com/package/underscore.template).
const targetElement = document.querySelector('#target')
// Define your template
const template = UnderscoreTemplate(
'<a class="<%- link.className %>" href="<%- link.url %>">\
<div class="<%- wrapper.className %>">\
<div class="<%- thumbnail.className %>">\
<img src="<%- thumbnail.image %>">\
</div>\
<div class="<%- info.className %>">\
<div class="<%- info.title.className %>"><%- info.title.text %></div>\
</div>\
</div>\
</a>');
// Define values for template
const obj = {
link: {
className: 'scoreboard-video-outer-link',
url: '#someurl'
},
wrapper: {
className: 'scoreboard-video--wrapper'
},
thumbnail: {
className: 'scoreboard-video--thumbnail',
image: 'http://via.placeholder.com/350x150'
},
info: {
className: 'scoreboard-video--info',
title: {
className: 'scoreboard-video--title',
text: 'Pelicans # Bulls Postgame: E`Twaun Moore 10-8-17'
}
}
};
// Build template, and set innerHTML to output element.
targetElement.innerHTML = template(obj)
// And of course you can go into forEach loop here like
const arr = [obj, obj, obj]; // Create array from our object
arr.forEach(item => targetElement.innerHTML += template(item))
<script src="https://unpkg.com/underscore.template#0.1.7/dist/underscore.template.js"></script>
<div id="target">qq</div>

Custom HTML element attribute not showing - Web-Components

I'm exploring web-components custom HTML elements, and I am running into a problem adding custom attributes to my custom elements: any value I set in the markup is never honored.
For a simple element like this, which should show the text supplied in the "flagtext" attribute, it does always show the default value.
<test-flag flagtext="my text"></test-flag>
Full JSBin sample is here.
The JSBin uses the Polymer library (as this is the only thing I can pull in there). I am using webcomponents.js generally, same result. Both in Chrome 49 and in Firefox 45 gives same result. There is no error showing in the console or debugger.
Every sample I find on the web has similar code but I tried various versions and it always refuses to update. I even copied a few samples into JSBin and they do not work either.
What could be wrong? I understand it is experimental technology but the consistency with which this isn't working is still surprising. Has this standard been abandoned? (I see that the latest April 2016 W3C draft of custom elements has entirely changed its approach.)
When I define "attributeChangedCallback" function, it does not fire.
I can easily modify the property via Javascript, this is not a problem.
But why can I not specify the property in markup, as I am supposed to?
Edit - full code
Note that you'll need to put these into separate files for the HTML import, and that you need the "webcomponents-lite.js" library.
Main HTML file
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
test-flag
{
border: 1px solid blue;
}
</style>
</head>
<body>
<script src="lib/webcomponents-lite.min.js"></script>
<link rel="import" href="test-flag.html">
Here is the custom test-flag component:
<p>
<test-flag flagtext="my text"></test-flag>
</body>
</html>
File: test-flag.html
<template>
<style>
</style>
Content:
<div id="testflagID">
</div>
</template>
<script>
(function() {
var _currentScript = (document._currentScript || document.currentScript);
var importDoc = _currentScript.ownerDocument;
var customPrototype = Object.create(HTMLElement.prototype);
Object.defineProperty(customPrototype, 'flagtext', {value: '(default)', writable: true});
document.registerElement('test-flag', {prototype: customPrototype});
customPrototype.createdCallback = function()
{
var template = importDoc.querySelector('template');
var clone = document.importNode(template.content, true);
var idx = clone.querySelector("#testflagID");
idx.textContent = this.flagtext;
var root = this;
var createdElement = root.appendChild(clone);
};
})();
</script>
There are 2 concepts that are not automatically linked together.
In the HTML code:
<test-flag flagtext="my text"></test-flag>
...term flagtext is an HTML attribute (not a property).
In the JavaScript code:
Object.defineProperty(customPrototype, 'flagtext', {value: '(default)', writable: true})
...term flagtext is a JavaScript property (not an attribute).
For standard elements, the browser automatically binds the property value to the attribute value (and vice versa). For Custom Elements, too (with standard attributes). But if you want to add a custom attribute, you'll have to bind it manually.
For example, in the createdCallback() method, add:
this.flagtext = this.getAttribute( 'flagtext' ) || '(default)'
Live sample:
document.registerElement( 'test-flag' , {
prototype: Object.create( HTMLElement.prototype, {
flagtext: {
value: '(default)',
writable: true
},
createdCallback: {
value: function()
{
this.flagtext = this.getAttribute( 'flagtext' ) || this.flagtext
this.innerHTML = 'flagtext=' + this.flagtext
}
},
} )
} )
<test-flag flagtext='new content'>Hello</test-flag>
NB: the attributeChangedCallback() method is fired only when an attribute is changed after element creation (which is not the case here).

Why does MathJax appear to toggle on and off as I type LaTeX?

I have "borrowed" the code below from other sources. As far as I can tell it is basically the same as
this MathJax demo page. The problem I'm having is that I don't see the results I have typed for odd numbered key presses. For example, when I type the first character I don't see anything in the MathPreview div. But, I see the first two characters after typing the second character. This pattern repeats so that it is as if MathJax toggles on for even key presses, but it turns off for odd numbered key presses. Any ideas why this is happening? This doesn't occur on the demo page I linked to above.
<!DOCTYPE html>
<html>
<head>
<title>Mathematics</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<link rel="stylesheet" href="assets/css/styles.css">
<script src="bower_components/MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script>
var Preview = {
delay: 150, // delay after keystroke before updating
preview: null, // filled in by Init below
buffer: null, // filled in by Init below
timeout: null, // store setTimeout id
mjRunning: false, // true when MathJax is processing
oldText: null, // used to check if an update is needed
// Get the preview and buffer DIV's
Init: function () {
this.preview = document.getElementById("MathPreview");
this.buffer = document.getElementById("MathBuffer");
},
// Switch the buffer and preview, and display the right one.
// (We use visibility:hidden rather than display:none since
// the results of running MathJax are more accurate that way.)
SwapBuffers: function () {
var buffer = this.preview, preview = this.buffer;
this.buffer = buffer; this.preview = preview;
buffer.style.visibility = "hidden"; buffer.style.position = "absolute";
preview.style.position = ""; preview.style.visibility = "";
},
// This gets called when a key is pressed in the textarea.
// We check if there is already a pending update and clear it if so.
// Then set up an update to occur after a small delay (so if more keys
// are pressed, the update won't occur until after there has been
// a pause in the typing).
// The callback function is set up below, after the Preview object is set up.
Update: function () {
if (this.timeout) {clearTimeout(this.timeout)}
this.timeout = setTimeout(this.callback,this.delay);
},
// Creates the preview and runs MathJax on it.
// If MathJax is already trying to render the code, return
// If the text hasn't changed, return
// Otherwise, indicate that MathJax is running, and start the
// typesetting. After it is done, call PreviewDone.
CreatePreview: function () {
Preview.timeout = null;
if (this.mjRunning) return;
var text = document.getElementById("MathInput").value;
if (text === this.oldtext) return;
this.buffer.innerHTML = this.oldtext = text;
this.mjRunning = true;
MathJax.Hub.Queue(
["Typeset",MathJax.Hub,this.buffer],
["PreviewDone",this]
);
},
// Indicate that MathJax is no longer running,
// and swap the buffers to show the results.
PreviewDone: function () {
this.mjRunning = false;
this.SwapBuffers();
}
};
// Cache a callback to the CreatePreview action
Preview.callback = MathJax.Callback(["CreatePreview",Preview]);
Preview.callback.autoReset = true; // make sure it can run more than once
</script>
<script type="text/x-mathjax-config;executed=true">
MathJax.Hub.Config({
showProcessingMessages: false,
tex2jax: { inlineMath: [['$','$'],['\\(','\\)']] }
});
</script>
</head>
<body>
<div class="content">
<div id="MathJax_Message" style="display: none;"></div>
<div class="left_half_page">
<div class="content">
<div class="fill_with_padding">
<textarea class="content no_border" id="MathInput" onkeyup="Preview.Update()"></textarea>
</div>
</div>
</div>
<div class="right_half_page">
<div class="content">
<div class="fill_with_padding">
<div id="MathPreview" class="content">
<div id="MathBuffer">
<div>
<script>Preview.Init();</script>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
The problem is that your MathBuffer and MathPreview are nested. They should be siblings. The code uses a double-buffering technique that shows one buffer while the other is being typeset, and then switches the two. One is displayed while the other is hidden. If one is inside the other, you will only see the result every other keystroke.
Also, note that the contents of the buffers are replaced by the input, and so when you replace the MathPreview buffer, you remove the MathBuffer and the script it contains. Note that in the MathJax page that you link to, the two div's (the MathPreview and MathBuffer) are not nested, and the initialization script occurs after both of them (not nested within them).
If you fix the nesting problems, I think it will work for you.

Marionette.js - can I detect onAppend?

I have a silly problem, where my only solution is a sloppy hack that is now giving me other problems.
See my fiddle,
or read the code here:
HTML:
<input id='1' value='input1' />
<template id='template1'>
<input id='2' value='input2' />
</template>
JS - Item View Declaration:
// Declare an ItemView, a simple input template.
var Input2 = Marionette.ItemView.extend({
template: '#template1',
onRender: function () {
console.log('hi');
},
ui: { input2: '#2' },
onRender: function () {
var self = this;
// Despite not being in the DOM yet, you can reference
// the input, through the 'this' command, as the
// input is a logical child of the ItemView.
this.ui.input2.val('this works');
// However, you can not call focus(), as it
// must be part of the DOM.
this.ui.input2.focus();
// So, I have had to resort to this hack, which
// TOTALLY SUCKS.
setTimeout(function(){
self.ui.input2.focus();
self.ui.input2.val('Now it focused. Dammit');
}, 1000)
},
})
JS - Controller
// To start, we focus input 1. This works.
$('#1').focus();
// Now, we make input 2.
var input2 = new Input2();
// Now we 1. render, (2. onRender is called), 3. append it to the DOM.
$(document.body).append(input2.render().el);
As one can see above, my problem is that I can not make a View call focus on itself after it is rendered (onRender), as it has not yet been appended to the DOM. As far as I know, there is no other event called such as onAppend, that would let me detect when it has actually been appended to the DOM.
I don't want to call focus from outside of the ItemView. It has to be done from within for my purposes.
Any bright ideas?
UPDATE
Turns out that onShow() is called on all DOM appends in Marionette.js, be it CollectionView, CompositeView or Region, and it isn't in the documentation!
Thanks a million, lukaszfiszer.
The solution is to render your ItemView inside a Marionette.Region. This way an onShow method will be called on the view once it's inserted in the DOM.
Example:
HTML
<input id='1' value='input1' />
<div id="inputRegion"></div>
<template id='template1'>
<input id='2' value='input2' />
</template>
JS ItemView
(...)
onShow: function () {
this.ui.input2.val('this works');
this.ui.input2.focus();
},
(...)
JS Controller
$('#1').focus();
var inputRegion = new Backbone.Marionette.Region({
el: "#inputRegion"
});
var input2 = new Input2();
inputRegion.show(input2);
More information in Marionette docs: https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.region.md#region-events-and-callbacks
Well, I managed to solve it by extending Marionette.js, but if anyone else has a better idea that doesn't involve extending a library, I will GLADLY accept it and buy you a doughnut.
// After studying Marionette.js' annotated source code,
// I found these three functions are the only places
// where a view is appended after rendering. Extending
// these by adding an onAppend call to the end of
// each lets me focus and do other DOM manipulation in
// the ItemView or Region, once I am certain it is in
// the DOM.
_.extend(Marionette.CollectionView.prototype, {
appendHtml: function(collectionView, itemView, index){
collectionView.$el.append(itemView.el);
if (itemView.onAppend) { itemView.onAppend() }
},
});
_.extend(Marionette.CompositeView.prototype, {
appendHtml: function(cv, iv, index){
var $container = this.getItemViewContainer(cv);
$container.append(iv.el);
if (itemView.onAppend) { itemView.onAppend() }
},
});
_.extend(Marionette.Region.prototype, {
open: function(view){
this.$el.empty().append(view.el);
if (view.onAppend) { view.onAppend() }
},
});

Categories