How to make TinyMCE work inside an UpdatePanel?

20,349

Solution 1

To execute the init everytime the UpdatePanel changes you need to register the script using ScriptManager:

// control is your UpdatePanel
ScriptManager.RegisterStartupScript(control, control.GetType(), control.UniqueID, "your_tinymce_initfunc();", true);

NOTE: You cannot use exact mode on your init function, you can use either textareas or a class selector, or else it won't work properly.

You also have to use

ScriptManager.RegisterOnSubmitStatement(this, this.GetType(), "", "tinyMCE.triggerSave();");

On a postback of a UpdatePanel the editor content isn't saved on the Textbox, because the default behavior is only for form.submit, so when you submit anything it will save the text before it posts.

On the code behind to get the value you will just need to access TextBox.Text property.

NOTE: If you are using the .NET GZipped you probably will have to drop it, I couldn't get it working, I had to remove this completely.

Solution 2

Ok, your problem is two fold. Stefy supplied you with part of the answer, which is you have to initialize TinyMCE on the postback by registering startup script like so:

using System.Web.UI;

namespace TinyMCEProblemDemo
{
    public partial class EditorClean : UserControl
    {
        protected void Page_Load(object sender, System.EventArgs e)
        {                
              ScriptManager.RegisterStartupScript(this.Page, 
                  this.Page.GetType(), mce.ClientID, "callInt" + mce.ClientID + "();", true);
        }
    }
}

The second problem you have is with your implementation of a custom control. Designing custom controls is out of scope of this answer. Google can help you there.

You have multiple instances of your control on the page which can cause you issues with script, as it get rendered multiple times. This is how I modified your markup to solve your issue(notice dynamic naming of your script functions, custom controls should be self contained and mode: "exact" on the tinyMCE.init):

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="EditorClean.ascx.cs"
    Inherits="TinyMCEProblemDemo.EditorClean" %>
<script type="text/javascript" src="Editor/tiny_mce.js"></script>

<script type="text/javascript">
    function myCustomCleanup<%= mce.ClientID%>(type, value) {
        if (type == "insert_to_editor") {
            value = value.replace(/&lt;/gi, "<");
            value = value.replace(/&gt;/gi, ">");
        }
        return value;
    }
    function myCustomSaveContent<%= mce.ClientID%>(element_id, html, body) {
        html = html.replace(/</gi, "&lt;");
        html = html.replace(/>/gi, "&gt;");
        return html;
    }

    function callInt<%= mce.ClientID%>() {

        tinyMCE.init({
            mode: "exact",
            elements: "<%= mce.ClientID%>",
            theme: "advanced",
            skin: "o2k7",
            plugins: "inlinepopups,paste,safari",
            theme_advanced_buttons1: "fontselect,fontsizeselect,|,forecolor,backcolor,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,cut,copy,paste,pastetext,pasteword",
            theme_advanced_buttons2: "",
            theme_advanced_buttons3: "",
            theme_advanced_toolbar_location: "top",
            theme_advanced_toolbar_align: "left",
            cleanup_callback: "myCustomCleanup<%= mce.ClientID%>",
            save_callback: "myCustomSaveContent<%= mce.ClientID%>"
        });
    }
</script>
<textarea runat="server" id="mce" name="editor" cols="50" rows="15">Enter your text here...</textarea>

Solution 3

This solution no longer works for TinyMCE 4.2.3. Instead of using tinymce.mceRemoveControl() you now need to use tinymce.remove(). Here is a full working example:

The Page

    <%@ Page Title="" Language="C#" MasterPageFile="~/MasterPages/Frame.master" AutoEventWireup="true" CodeFile="FullImplementation.aspx.cs" 
  Inherits="TinyMCE" ValidateRequest="false" %>

<asp:Content ID="Content1" ContentPlaceHolderID="cphContent" Runat="Server">

  <asp:ScriptManager runat="server"/>


  <asp:UpdatePanel runat="server" id="upUpdatPanel">
    <ContentTemplate>

      <asp:TextBox runat="server" id="tbHtmlEditor" TextMode="MultiLine">
        Default editor text
      </asp:TextBox>

      <asp:Dropdownlist runat="server" ID="ddlTest" AutoPostBack="true" OnSelectedIndexChanged="ddlTest_SelectedIndexChanged">
        <Items>
           <asp:ListItem Text="A"></asp:ListItem>
           <asp:ListItem Text="B"></asp:ListItem>
        </Items>
      </asp:Dropdownlist>

      <asp:Button runat="server" ID="butSaveEditorContent" OnClick="butSaveEditorContent_Click" Text="Save Html Content"/>      

    </ContentTemplate>
  </asp:UpdatePanel>

  <script type="text/javascript">

      $(document).ready(function () {
        /* initial load of editor */
        LoadTinyMCE();
      });

      /* wire-up an event to re-add the editor */     
      Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler_Page);

      /* fire this event to remove the existing editor and re-initialize it*/
      function EndRequestHandler_Page(sender, args) {
        //1. Remove the existing TinyMCE instance of TinyMCE
        tinymce.remove( "#<%=tbHtmlEditor.ClientID%>");
        //2. Re-init the TinyMCE editor
        LoadTinyMCE();
      }

      function BeforePostback() {
        tinymce.triggerSave();
      }

      function LoadTinyMCE() {

        /* initialize the TinyMCE editor */
        tinymce.init({
          selector: "#<%=tbHtmlEditor.ClientID%>",
          plugins: "link, autolink",
          default_link_target: "_blank",
          toolbar: "undo redo | bold italic | link unlink | cut copy paste | bullist numlist",
          menubar: false,
          statusbar: false
        });
      }

  </script>




</asp:Content>

The Code-Behind:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class TinyMCE : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    // we have to tell the editor to re-save the date on Submit 
    if (!ScriptManager.GetCurrent(Page).IsInAsyncPostBack)
    {
      ScriptManager.RegisterOnSubmitStatement(this, this.GetType(), "SaveTextBoxBeforePostBack", "SaveTextBoxBeforePostBack()");
    }

  }

  protected void butSaveEditorContent_Click(object sender, EventArgs e)
  {
    string htmlEncoded = WebUtility.HtmlEncode(tbHtmlEditor.Text);

  }

  private void SaveToDb(string htmlEncoded)
  {
    /// save to database column
  }

  protected void ddlTest_SelectedIndexChanged(object sender, EventArgs e)
  {

  }
}

Solution 4

The correct way to make tinyMCE work in an updatepanel:

1) Create a handler for the OnClientClick of your "submit" button.

2) Run tinyMCE.execCommand("mceRemoveControl", false, '<%= txtMCE.ClientID %>'); in the handler, so as to remove the tinyMCE instance before the postback.

3) In your async postback, use the ScriptManager.RegisterStartupScript to run tinyMCE.execCommand("mceAddControl", true, '<%= txtMCE.ClientID %>');

Basically, all you need to do is use the mceRemoveControl command before the async postback and register a startup script to run the mceAddControl command after the async postback. Not too tough.

Solution 5

Updating the answer to this question for those using .NET framework 4, I was successful in attaching TinyMCE to a TextBox inside an update panel by inserting the following:

In markup within the <head></head> region:

<script src="scripts/tinymce/tinymce.min.js" type="text/javascript"></script>
<script type="text/javascript">

    tinyMCE.init({
        selector: ".tinymcetextarea",
        mode: "textareas",

        plugins: [
             "advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker",
             "searchreplace visualblocks visualchars code fullscreen autoresize insertdatetime media nonbreaking",
             "save table contextmenu directionality emoticons template paste textcolor",
             "autosave codesample colorpicker image imagetools importcss layer"
        ],

        toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media | forecolor backcolor emoticons",
        style_formats: [
             { title: 'Bold text', inline: 'b' },
             { title: 'Red text', inline: 'span', styles: { color: '#ff0000' } },
             { title: 'Red header', block: 'h1', styles: { color: '#ff0000' } },
             { title: 'Example 1', inline: 'span', classes: 'example1' },
             { title: 'Example 2', inline: 'span', classes: 'example2' },
             { title: 'Table styles' },
             { title: 'Table row 1', selector: 'tr', classes: 'tablerow1' }
        ]
    });

</script>

In the markup within the <body></body> region:

<asp:TextBox ID="tbContentHtml" CssClass="tinymcetextarea" Wrap="true" runat="server" Width="90%" TextMode="MultiLine" />

And finally in codebehind in the Page_Load event:

ScriptManager.RegisterStartupScript(this, this.GetType(), tbContentHtml.UniqueID + "Add", "tinyMCE.execCommand('mceAddEditor', true,'" + tbContentHtml.ClientID + "');", true);
ScriptManager.RegisterOnSubmitStatement(this, this.GetType(), tbContentHtml.UniqueID + "Remove", "tinyMCE.execCommand('mceRemoveEditor', true,'" + tbContentHtml.ClientID + "');");
Share:
20,349
jpsimard-nyx
Author by

jpsimard-nyx

I work as a .Net programmer. Prefered language C#. Mostly worked on web project in ASP.NET.

Updated on February 21, 2020

Comments

  • jpsimard-nyx
    jpsimard-nyx about 4 years

    I'm trying to do something that many people seem to have been able to do but which I am unable to implement any solution. The TinyMCE control works pretty well in an asp.net form until you enclose it with an UpdatePanel, which then breaks after postback. I have tried some fixes like the RegisterClientScriptBlock method, but am still unsuccessful, I still lose the tinyMCE control after postback.

    Below is a full test project (VS 2008) provided with a Control outside UpdatePanel and one inside, with a button on each to generate postback. Also in the project I have a EditorTest control which include commented code of some calls I tried, in case it gives anyone any ideas.

    CODE SAMPLE

    Here are some sources for some solutions on the MCE forum :
    AJAX
    UpdatePanel

  • jpsimard-nyx
    jpsimard-nyx about 15 years
    This has nothing to do with my problem where my postbacks are working, it's the tinyMCE layout that doesn't rebuild. Encoding the <> tag fix the validationRequest problem and I already did it. The code sample provided do not include such errors.
  • BrunoLM
    BrunoLM over 13 years
    You cannot use the mode "exact", it doesn't work properly in a UpdatePanel. You can use textareas or a class selector instead. And for me the save_callback was pretty buggy, instead I used RegisterOnSubmitStatement to call tinyMCE.triggerSave(). It's working just fine for me.
  • rick schott
    rick schott over 13 years
    I have used mode exact in UpdatePanels without issue, everyone's requirements and implementation details are different.
  • Red Taz
    Red Taz over 10 years
    I too spent hours searching. Turns out in version 4 the above TinyMCE commands have been replaced with mceAddEditor / mceRemoveEditor tinymce.com/forum/viewtopic.php?id=31256
  • Jaime
    Jaime about 7 years
    This is definitely the solution. It also works for TinyMCE Version 4.5.4 and works across the all browsers (tested on Chrome Version 56, IE 9, 10, 11, and Microsoft Edge 38). Other possible solutions that don't use .remove() failed to work on browsers other than IE. Also, you can pass the class name to .remove(<class_name>), which is what I do and works great. Thanks @bperniciaro for this solution!
  • Ajmal Jamil
    Ajmal Jamil over 6 years
    Great solution (y)
  • Taylor Brown
    Taylor Brown almost 6 years
    This worked for me inside of my .ascx user control, put it in Page_Load. Someone may find this comment helpful.
  • Taylor Brown
    Taylor Brown over 3 years
    As of this week every instance of this in all of my code stopped working. 2020-09-01 - working hard to find a solution, but tinyMCE.triggerSave() now throws an exception of [Cannot read property 'body' of null] every single time.