It's a sad fact that Blaze (Meteor's reactive UI library) doesn't play particularly well with contenteditable elements. The corresponding ticket in GitHub is marked as closed but the issue itself is unfortunately far from resolved.

This makes implementing e.g. autosave for contenteditable elements quite annoying - say you're throttling the keypress event and saving every two or three seconds. However, when you save the document to Mongo, reactivity kicks in and the text in contenteditable randomly gets duplicated and/or the caret jumps somewhere (read: the contenteditable is pretty much rendered unusable). Incredibly frustrating.

There's a couple workarounds suggested in the GitHub issue comments but none of them works particularly great - in general they are either too complicated or they have issues with focus getting lost.

Which is why my colleague, Alon, came up with a workaround that is actually quite simple and preserves focus and caret position.

What we need to do is to essentially opt-out from Blaze's reactivity for the contenteditable element. When we save the content, we don't want Blaze to re-render it based on the stored version (which, in case we're throttling the keypress event, will often be behind the actual content). So how do we do that?

The idea is based on the fact that Blaze is trying to do as little work as it can when re-rendering the DOM (because reflows/repaints are expensive). This means that when we use a template helper and its value does not change, Blaze knows it does not need to re-render the corresponding DOM tree...and so it won't.

Now, what we want to do is to persuade Blaze the value of the helper that affects the contenteditable element never changes after it's rendered, i.e., we want to turn it into a constant function. In order to do this, we need to somehow tap into the lifecycle of the relevant Blaze template - lucky for us, Blaze provides a created callback which gets called before anything gets rendered and before any helpers are called.

Which in other words means we can do this:

MyTemplate.created = function () { = {

  myEditableHelperContent: function () {
    var instance = Template.instance();
    return instance.__values_override__.editableContent;

Now we can be sure Blaze will load the contents of the editor from Mongo when the relevant DOM tree is first rendered and that it will then not mutate the content under our hands afterwards (because we've turned the helper into a constant function so Blaze will never try to re-render it).

Pretty? Not particularly. Functional? Very. :-)

Happy meteoring! I'm @tomas_brambora.