Dynamically Adding and Removing TinyMCE Instances to a Page

Thursday, 13 November 2008

TinyMCE is a pretty neat tool for adding some WYSIWYG editing features to standard HTML textarea and div tags. Out of the box it's pretty easy to install and use, but I ran into some trouble trying to dynamically load and unload editor instances to a textarea that was injected into the DOM via Ajax. Turns out that I was trying to instantiate the editor instance before the textarea tag had been unhidden which caused TinyMCE to choke and die for some reason.

What follows is a quick overview on how to instantiate TinyMCE dynamically.

Once you've installed TinyMCE, in your main template you'll want to create a base configuration for the TinyMCE instances you'll be using:

<script type="text/javascript" charset="utf-8">
	tinyMCE.init({
		mode : "none",
		theme : "simple"
	});
</script>

You'll notice that we're using the mode "none" here. This basically sets up TinyMCE without actually transforming any of the text fields on the page. This is the only thing that's really important. You can of course use the advanced theme, but I'm using the simple theme for brevity.

At this point, you can do whatever you need to do in the DOM to add and remove text areas dynamically. To attach an instance of TinyMCE to a (dynamically loaded) text area, just do this after the insertion:

tinyMCE.execCommand('mceAddControl', false, 'the_textareas_id_here');

… and if you're going to remove that text area dynamically, do this before removing it:

tinyMCE.execCommand('mceFocus', false, 'the_textareas_id_here');                    
tinyMCE.execCommand('mceRemoveControl', false, 'the_textareas_id_here');

I use the "mceFocus" command before removing the instance because I've read that without it IE will sometimes fail. Also, you can do something like this if you want to make sure the TinyMCE instance exists before trying to remove it:

if (tinyMCE.getInstanceById('the_textareas_id_here'))
{
	tinyMCE.execCommand('mceFocus', false, 'the_textareas_id_here');                    
	tinyMCE.execCommand('mceRemoveControl', false, 'the_textareas_id_here');
}

Since TinyMCE doesn't actually use the original textarea to do it's magic, you'll have to trigger a command to repopulate the original textarea tag with the modified contents before further manipulating the data:

tinyMCE.triggerSave();

If it's not completely obvious, the reason you have to jump through all these hoops is because TinyMCE does some interesting things in the background in order to make it look and feel like you're using a real text editor. This involves some intricate DOM manipulation and hackery.

All in all, I've found that this method works very well in practice. Again, just be sure that the element you're adding the TinyMCE instance to isn't hidden in the DOM. For some reason this'll kill TinyMCE and you'll end up with a blank editor that doesn't work. In FireFox this was often seen as the dreaded t.win.document is null error.