Using TinyMCE with an AJAX form submit

I never thought getting TinyMCE to work with an AJAX post would be difficult, but a day of poking and prodding (with eventual success), brought me back to reality and reminded me how useful a browser Developer Toolbar can be.

The more I work with AJAX technologies, the more I like working away from the typical get/post page life-cycle. Developers can have dozens of pages for different functions, yet still place all the server-side validation and database connectivity code in one ajax end-point. It may not work in every environment, but in a managed corporate environment it works just fine.

TinyMCE is probably the premiere (free) browser based publishing tool, but if you have ever explored the DOM tree of a page that uses TinyMCE, you will see that all of the coolness is actually embedded in an IFRAME, which adds some complexity when applying validation to the contents, or in the case of an AJAX call, getting the content.


The trick to the process is realizing that TinyMCE uses the page unload event as a trigger to move all the content back into the TextArea that the instance of TinyMCE is tied to. The function that the unload event calls is the “triggerSave” function that you can see on line 467 of the “tiny_mce_src.js” file. This function performs some tiny magic and then moves the contents from the IFRAME into the TextArea.

So the javascript function that does the AJAX call needs to first call the triggerSave function. Couple this knowledge with our handy-dandy protoype.js library ajax calls, and it all comes together quite nicely.


function postForm(){
		tinyMCE.triggerSave(true,true);
		var mceContent = escape($F('myTextArea'));
		var otherContent = $F('someField');
		var url = 'http://yoursever/app/post_content';
		var pars = 'body=' + mceContent + '&other=' + otherContent;
		var myAjax = new Ajax.Request( 
				url, 
				{ 
						method: 'post', 
						parameters: pars, 
						onComplete: showResponse 
				}
		);
	}

Remember to POST when you have alot of content since a GET places all of the parameters into the URL of the request and you can run into some serious limitations with respect to maximum URL lengths.

26 Responses to “Using TinyMCE with an AJAX form submit”

  1. AJ Says:

    Howdy, cheers for the tip, I think it will come in very handy when I get to that stage. But a quick question I have too and maybe you have come across this. When generating a form from an ajax request, the textarea that is targeted doe snot load, in fact the whole browser loads up this mad window of whiteness… anyhow, will let you know it I figure it out. Thanks for sharing.

  2. Administrator Says:

    Having never attempted to load a TinyMCE form from an AJAX call, all I can offer is opinions. If you load the body into the textarea with the ajax call, I would think you would need to call the init() function at the end of the ajax function. Something like:

    tinyMCE.init({mode : “textareas”,theme : “simple”});

    What have you attemped so far?

  3. Administrator Says:

    Well, one last thought for the day, I remember there was a function of TinyMCE called “updateContent” that would copy the value of a given document element into the TinyMCE instance that is tied to it. It seems this function may be made for exactly what you are attempting. So populate the textarea with the ajax call, then update:

    TinyMCE.updateContent(’textarea_id’)

  4. B-square Says:

    Dude thanks for sharing this research. A small note, however. The object you refer to in your code-snippet should be tinyMCE.triggerSave(true,true); (not the extra ‘y’ - probably a typo).

  5. Administrator Says:

    DOOH!!!

    thanx 4 the tip!

  6. kito Says:

    This tip was invaluable for getting my AJAXed comments form working. Thanks for that. For those readers who are using AJAX to generate the textarea as well, it might help to add this script:

    tinyMCE.execCommand(’mceAddControl’, true, ‘textarea_name’)

    To the partial form that you’ll be loading. This has the effect of initializing TinyMCE on the textarea specified, since it didn’t exist when the page initially loaded.

  7. kito Says:

    oops, I got sanitized on that one, just in case it wasn’t clear, it should look like this:

    < script type=”text/javascript” >
    tinyMCE.execCommand(’mceAddControl’, true, ‘comment[content]’)
    < /script >

    hopefully that displays properly.

  8. davorin Says:

    thanks kito, your comment really helped me.
    i was building a small ajax thingy (something of mine, a small cms, if you could call it that ;-) ).
    so i put this on top of my main page:

    tinyMCE.init({
    mode : “textareas”,
    auto_reset_designmode : true
    });

    and this one into my request onload function that is executed when my ajax request function loads the page (an event basically)

    requestOnLoad = function(){

    tinyMCE.execCommand(’mceAddControl’, true, ‘articleEditor’);
    }

    thaks again

  9. Onno Schuit Says:

    Hi,

    Thanks for all the tips. I got tinyMCE working in an ajax context (in Ruby on Rails), but only in MS IE. In Firefox, tinyMCE does not save upon the SECOND submit.

    It says somewhere: “If you load a TinyMCE form from an AJAX call, Firefox saves the content only once, even if you use auto_reset_designmode : true.” So included this in my initialization:

    I have got this code to init tinyMCE:

    tinyMCE.init({
    mode:”textareas”, editor_selector : “tiny_mce”,
    language : “nl”,
    theme: “simple”,
    auto_reset_designmode : true
    });

    The textarea code is in rhtml (Ruby on Rails):

    “height:50px;width:350px;” %>

    And this is my submit button:

    Whenever I submit the tinyMCE content for the SECOND time (i.e. 2nd save), Firefox tells me:

    this.getDoc() has not properties
    ../javascript/tiny_mce/tiny_mce.js

    In MS IE, no problems whatsoever.

    Cheers,
    Onno

  10. Onno Schuit Says:

    My code got mangled. Let’s try that again:

    My text area code (in Ruby on Rails):

    <%= text_area ‘exercise’, ‘question’ , :style => “height:50px;width:350px;” %>

    My submit button:

    <input class=”submit” onclick=”tinyMCE.triggerSave(true,true);” type=”submit” value=”Bewaren”/>

    And the code to actually add a tinyMCE instance to the page:

    tinyMCE.execCommand(’mceAddControl’, true, ‘exercise_question’);

    Cheers,
    Onno

  11. Onno Schuit Says:

    I have found the solution to the ajax troubles with TinyMCE in Firefox:

    http://tinymce.moxiecode.com/punbb/viewtopic.php?pid=10867#p10867

    Which says basically: before adding a new mce control, first set the id counter to zero

    tinyMCE.idCounter=0;
    tinyMCE.execCommand(’mceAddControl’, true, ‘exercise_question’);

    Cheers!
    Onno

  12. John Says:

    Can some explain where to put that code for a newb? Thanks.

  13. Gabriel Zamprogna Says:

    R u all crazy? Never use encodeURIComponent(tinyMCE.getContent())? Cheers!

  14. Ryan Says:

    Another solution I used to solve the problem is upon submit or page change convert the editor back to a textarea like so:

    tinyMCE.execCommand(’mceRemoveControl’, false, ‘instanceName’);

    Make sure to replace ‘instanceName’ with the name of the instance you want to replace.

    This way you just access it like a normal form element

    Best of luck!

  15. Katipo Developers Blog » Blog Archive » Rails: Integrating the TinyMCE plugin into ajaxscaffold generated forms Says:

    […] Ok, the controller is taken care of. At this point according to comments I found here you might be able to use it with IE, but it needs more massaging to work with Firefox. So onto our views to put in place the necessary adjustments. […]

  16. toannh Says:

    tiny mce does not work when change content of div with ajax !!! help ????

  17. toannh Says:

    I used XmlHttpRequest for change content of div.

  18. kuba Says:

    I’ve use TinyMCE without form or textarea, with little modification

    I’ve add in tiny_mce.js in init function (ajax parameter):

    this._def(”ajax”, false);

    and in save plugin in editor_plugin.js

    if(formObj||inst.getParam(’ajax’)) {
    …..

    [ ]

    function ajax_post(tinyInstance) {
    sendAjaxRequest(tinyInstance.getBody().innerHTML());
    }

    tinyMCE.init({
    mode:”exact”,
    elements: “editor”,
    ajax: true,
    plugins: “save”,
    theme: “advanced”,
    save_onsavecallback: “ajax_post”,
    theme_advanced_buttons1_add_before: “save,separator”,

    });

    [ ]

    With this you can use save plugin for sending ajax request.

  19. kuba Says:

    Sorry for previous post it eats html tags:

    I’ve use TinyMCE without form or textarea, with little modification

    I’ve add in tiny_mce.js in init function (ajax parameter):

    this._def(”ajax”, false);

    and in save plugin in editor_plugin.js

    if(formObj||inst.getParam(’ajax’)) {
    …..

    This is html file

    [script]
    function ajax_post(tinyInstance) {
    sendAjaxRequest(tinyInstance.getBody().innerHTML());
    }

    tinyMCE.init({
    mode:”exact”,
    elements: “editor”,
    ajax: true,
    plugins: “save”,
    theme: “advanced”,
    save_onsavecallback: “ajax_post”,
    theme_advanced_buttons1_add_before: “save,separator”,

    });
    [/script]

    [body]
    [div id=”editor”][/div]
    [/body]

    With this you can use save plugin for sending ajax request.

  20. toannh Says:

    please more detail ?

  21. Follower Says:

    Thank you so much for your knowledge!
    You just saved me a hour’s worth of work!

  22. Benjamin Says:

    I implemented kuba’s trick to do an ajax save. My only difference was that I called the parameter save_ajax in stead of just ajax. Since this is so easy, maybe this can be implemented in the new builds. Saves us changing the tinyMCE code for every new release. There are just two minor adjustments, but I’m lazy :-)

  23. Maurice Fonk Says:

    You may want to have a look at a handy hash function in prototype which takes care of the asking-for-typos ‘body=’ + mceContent + ‘&other=’ + otherContent;’-bit and the serialization / url-encoding issue mentioned earlier in the comments. You can basically put your variables in a hash and call toQueryString on that hash. You do NEED some kind of encoding, as the raw output of tinyMCE can contain HTML-entities which start with an ampersand (&), which would break the string given to pars in the Request.

    More info at http://www.prototypejs.org/api/hash/toQueryString

  24. Mr Jon Says:

    I’m trying to use ajax to auto-save the tinyMCE document. It’s running a triggerSave and ajax request every few seconds.

    When using tinyMCE.triggerSave(true,true); the cursor is always reset to the very top.

    Does anyone know a way to keep the cursor in the same place through the call?

  25. H Says:

    Thanks Onno Schuit

    that tinyMCE.idCounter=0; was a life saver :)

  26. yohann Says:

    Using ruby on rails with ajax request and submit…i can’t edit a link..Do i have to do somthing special to access this functionality ? the other popup windows seem to work normally otherwise…