Save RadEditor content to database without a button

0 Answers 75 Views
Editor Splitter
Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
Jeff asked on 07 Jan 2022, 09:15 PM

I have a RadEditor (EditType="Inline"), inside a RadSplitter/RadPane, and would like to trigger a post back to save to the database, without using a Button click.  

Which event is most appropriate to do this? 

I've experimented with the OnClientInlineEditCompleted() event.  However, it also fires when I click a toolbar button, which is too soon. 

The OnClientCommandExecuted() event fires with almost every action, so not good solution. 

In the server-side database save method, I compare the existing data to the RadEditor content, if they're different, save it to the database.  The problem here is that the changes made to the RadEditor do not show, thus the server-side save method is not fired.

I've attempted to set the focus back to the content of the RadEditor before calling the "__doPostBack()" method, thinking it will accept the changes to the content and save them in the PostBack.  It doesn't.

Client code:

function OnClientInlineEditCompleted() {
     var editor = $find("<%= NotePad1.ClientID %>");
     editor.setFocus();

      __doPostBack("", "");
}

 

PostBack code:

if (NotePad1.Content != MyTable.MyNotePad)
{
     UpdateNotePad();
}

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 11 Jan 2022, 01:52 PM

Update:  I've been able to get this logic to work *almost* as desired by setting a boolean "isUpdated" variable in the OnClientInlineEditCompleted event, then reacting to that value in the OnClientCommandExecuted event.  

Where it fails is when there is a dialog involved.  For example, when clicking the link button in the toolbar, this causes the events to fire and trigger the postback database save.

It seems I'm close, I just need to figure out how to suppress those dialogs until the user is done editing.

Vessy
Telerik team
commented on 11 Jan 2022, 04:48 PM

Hi Jeff, 

Can you, please, send me the RadEditor setup that you are using? I tested the provided logic and the OnClientInlineEditCompleted event is triggered at my end only when I click outside the Editor and its toolbar. You can see the video from my test here:

http://somup.com/c3VXDHZ2Z1

Below is the code I used with the latest version of the controls:

        <div style="margin-top: 100px">
            <telerik:RadEditor EditType="Inline" ID="NotePad1" runat="server"
                OnClientInlineEditCompleted="OnClientInlineEditCompleted">
                <Content>
        <div style="width: 420px">
            <h2 class="titleText">RadEditor for ASP.NET AJAX</h2>
            <p style="text-align: justify;">
                <span style="color: #4f6128; font-size: 19px;"><strong>RadEditor</strong></span><span style="color: #4f6128;">
                </span>is not simply an HTML
                <a href="#HTMLDescription">
                    <sup>1</sup>
                </a> Editor. It is what Microsoft chose to use in <strong>MSDN</strong>, <strong>CodePlex</strong>, <strong>TechNet</strong>, <strong>MCMS</strong> and even as an alternative to the default editor in
                <a href="https://www.telerik.com/products/aspnet-ajax/sharepoint.aspx">SharePoint</a>.
            </p>
        </div>
                </Content>
            </telerik:RadEditor>
            <asp:Label ID="Label1" runat="server"></asp:Label>

        </div>
        <script>
            function OnClientInlineEditCompleted() {
                alert("OnClientInlineEditCompleted");
                var editor = $find("<%= NotePad1.ClientID %>");
                editor.setFocus();


                __doPostBack("", "");
            }
        </script>

    protected void Page_Load(object sender, EventArgs e)
    {
        if (IsPostBack)
        {
            if (NotePad1.Content != Label1.Text)
            {
                UpdateNotePad();
            }
        }
    }

    private void UpdateNotePad()
    {
        Label1.Text = NotePad1.Content;
    }

 

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 11 Jan 2022, 06:12 PM

Vessy,

The video of your test is precisely the behavior I'd like to see.  Below is a screenshot of my RadEditor setup.  One big difference is I'm using the .axd DialogHandler.

I also made a quick little video of the postback occurring when I click on any tool that fires a dialog.  I've cropped it in order to protect proprietary content, so you can't see the dialog window pop-up, as it's off-screen, but you can clearly see the postback.  It was blocked from being attached to this message.  Please let me know how I can get this to you, if you deem it necessary to view.

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 11 Jan 2022, 06:40 PM

To clarify, this isn't just happening with tools that fire a dialog.  It's occurring with any toolbar button click.  The difference is that with simple tools like bold, italics, underline, etc., those changes get made prior to saving to the database.  Whereas any dialog appears briefly, then disappears when the postback happens, rendering it useless.
Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 12 Jan 2022, 03:23 PM

Vessy,

I replaced my RadEditor with the example you provided and all accompanying logic to mimic your setup - yielding the same results.  The postback occurs with every toolbar button click.

I'm at a loss as to what is causing this behavior.  As I mentioned, this RadEditor resides within a Splitter and Pane - could it be that either of those controls are the culprit?

Will test the RadEditor outside of the Splitter to see if the results are different.  Outside of using the alternate DialogHandler (.axd), that's the only difference.

Jeff.

Vessy
Telerik team
commented on 12 Jan 2022, 03:40 PM

Hi Jeff,

Usually a PostBack occurs on every button click when there is a JavaScript error thrown on the page. Can you verify if this is not the case at your end as well?

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 12 Jan 2022, 03:46 PM

Vessy,

That is one of the first things I looked at.  Just double-checked it and the console does not indicate any JS errors. 

 

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 12 Jan 2022, 05:54 PM

Vessy,

Something I've failed to mention, and could be the issue, is that we're using an "external" toolbar.  Here's the HTML:


<div>
                            <asp:Panel runat="server" ID="ToolbarHolder">
                                <div id="toolbarDiv" class="RadEditor reCustomContainer">
                                </div>
                            </asp:Panel>
                        </div>
                        <telerik:RadEditor ID="reNotePad" runat="server" Width="100%" Height="100%" RenderMode="Lightweight" 
                            ForeColor="SteelBlue" Font-Names="Comic Sans MS" BorderStyle="None" EmptyMessage="Enter your notes here ..."
                            OnClientInlineEditCompleted="OnClientInlineEditCompleted" OnClientLoad="OnClientLoad" OnClientCommandExecuted="OnClientCommandExecuted"
                            EditModes="Design" EditType="Inline" Visible="true" DialogHandlerUrl="~/Telerik.Web.UI.DialogHandler.axd" NewLineMode="Br"> 
                            <Tools>
                                <telerik:EditorToolGroup dockingzone="toolbarDiv">
                                    <telerik:EditorTool Name="Undo" />
                                    <telerik:EditorTool Name="Redo" />
                                    <telerik:EditorSeparator />
                                    <telerik:EditorTool Name="Bold" />
                                    <telerik:EditorTool Name="Italic" />
                                    <telerik:EditorTool Name="Underline" />
                                    <telerik:EditorSeparator />
                                    <telerik:EditorTool Name="ForeColor" />
                                    <telerik:EditorTool Name="BackColor" />
                                    <telerik:EditorSeparator />
                                    <telerik:EditorTool Name="InsertOrderedList" />
                                    <telerik:EditorTool Name="InsertUnorderedList" />
                                    <telerik:EditorSeparator />
                                    <telerik:EditorTool Name="InsertHorizontalRule" />
                                    <telerik:EditorSeparator />
                                    <telerik:EditorTool Name="Indent" />
                                    <telerik:EditorTool Name="Outdent" />
                                    <telerik:EditorSeparator />
                                    <telerik:EditorTool Name="InsertLink" />
                                    <telerik:EditorSeparator />
                                    <telerik:EditorTool Name="JustifyLeft" />
                                    <telerik:EditorTool Name="JustifyCenter" />
                                    <telerik:EditorTool Name="JustifyRight" />
                                    <telerik:EditorTool Name="JustifyFull" />
                                </telerik:EditorToolGroup>
                            </Tools>
                        </telerik:RadEditor>

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 14 Jan 2022, 02:53 PM

Here is the css used to style this Editor:


/*css to format inline radeditor form My Notepad*/
.RadEditor.RadWindow.reInlineEditor.reToolbarWindow.reWrapper {
    box-shadow: none !important;
    border-style: none !important;
    visibility: hidden !important;
}
.RadWindow.reInlineEditor .rwContent { /*cannot remove or client change won't fire*/
    background-color: transparent !important;
    color: transparent !important;
}
.RadEditor.reInlineEditor .reContentArea {
    font-size: 12px !important;
    padding: 50px 2px 2px 2px !important;
    position: center;
}


.RadEditor.reCustomContainer {
    border-style: none !important;
    background-color: #dee3ed;
    position: fixed;
    margin-right:51px;
    z-index: 50000;
}

Vessy
Telerik team
commented on 14 Jan 2022, 07:59 PM

Thanks a lot for the additional details, Jeff.

The faced problem is caused due to the fact the OnInlineEditCompleted event is triggered if you click either outside the editor, either outside the RadWindow holding the floating inline toolbar. The main specific of the inline edit mode of the Editor is that its toolbar is floating, thus it cannot be docked.

As you are docking the toolbar into a separate element outside the RadWindow wrapper, each click over the toolbar is now considered as a click outside the toolbar. That's why the docking zone could be used only when the Normal EditMode of the Editor is used.

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 17 Jan 2022, 01:08 PM

Thanks, Vessy.  We expected as much.  Wanted to get your thoughts on our approach.  We're able to catch the active element in the OnClientInlineEditCompleted event - if the active element is the toolbar (which we've designated with a class name), then we do not call the postback, and instead we want to shift focus back to the content area of the editor, so that when the user then clicks away from the editor, the postback will trigger.  It seems like we're on the verge of a usable solution, it's just that I've been unable to properly focus/select the content area.  Here's the code, would like to get your take on it how to do this:


function OnClientInlineEditCompleted() {

                let parentClass;
                
                try {
                    parentClass = document.activeElement.parentElement.parentElement.parentElement.parentElement.className;
                } catch (e) {
                    parentClass = '';
                }
               
                if (parentClass == "panel-editor-toolbar") {
                    var editor = $find("<%=reNotePad.ClientID%>"); // get a reference to RadEditor client object
                    
                    editor.setFocus();
                    //editor.get_contentArea().focus();
                } else {
                    __doPostBack("", "");
                }
            }

Vessy
Telerik team
commented on 18 Jan 2022, 02:56 PM

Hi Jeff,

Can you elaborate a bit on what behavior do you expect when focusing the Editor? The editor.setFocus() method focusses the Editor's iframe, you can check that by calling document.activeElement in the console of the page.

If you want to position the cursor inside the Editor after the focusing, you can follow the approach explained here:

https://www.telerik.com/forums/set-focus-to-the-end-of-text

 

 

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 18 Jan 2022, 03:37 PM

Vessy,

We're trying to mimic the user clicking into the content area after a toolbar button click, so that when they then click outside the content area, the postback will get triggered from the OnInlineEditCompleted event.

I actually got this to work yesterday, albeit in a strange way.  I added some JavaScript ("editor.hasFocus()") which has an error (the Editor does not have a "hasFocus() method".  This error caused the event to delay long enough to be able to produce the desired result.

I don't want to have an error solve my problem, so I thought I'd replace it with a setTimer function, but that didn't work.  So, I'm left with the expected outcome but with a javascript error.  So strange.

I'm now looking into why the JavaScript error is working this way, and implement some logic that does the same thing without throwing an error.


function OnClientInlineEditCompleted() {

                let parentClass;

                // Handle exception thrown when clicking on the body or any other element without four parents
                try {
                    parentClass = document.activeElement.parentElement.parentElement.parentElement.parentElement.className;
                } catch (e) {
                    parentClass = '';
                }
               
                if (parentClass == "panel-editor-toolbar") {
                    var editor = $find("<%=reNotePad.ClientID%>"); //get a reference to RadEditor client object
                    editor.setFocus();

                    // This if statement throws a javascript error
                    // The byproduct of this is that the postback triggers as desired
                    if (editor.hasFocus()) { alert("Editor has focus"); }
                    
                    //setTimeout(() => {
                    //    // Delay processing to ensure Editor regains focus
                    //    // in time to trigger postback
                    //}, 1000);

                } else {
                    __doPostBack("", "");
                }
            }

 

 

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 19 Jan 2022, 03:17 PM

Vessy,

Adding further clarification, as this issue is quickly becoming fluid:  What we noticed is that when you click on a toolbar button, then click outside the content, the OnClientInlineEditCompleted() event does not fire.  However, once you click inside the content area again (immediately following a toolbar button click), then click outside the content area, the event/postback is executed properly.

The idea is to automate this step of clicking back into the content area after the toolbar button click.  It appears that I've successfully done so.. unfortunately, an unhandled exception is the reason it is succeeding.  Interestingly ironic.

 

Vessy
Telerik team
commented on 20 Jan 2022, 05:59 PM

Hi Jeff,

When a JavaScript error is thrown on the page it prevents the execution of the remaining part of the client-side logic, hence the postback is not made when you call the unexisting hasFocus() method. Every error on the page prevents the proper functioning of the client-side logic of our controls as well (like the not propered call of the OnClientInlineEditCompleted event), making the usage of this hack strongly not recommended.

Did you have the chance to try the solution suggested in my previous reply? It should be similar to:

    <script>
        function OnClientInlineEditCompleted() {

            let parentClass;

            // Handle exception thrown when clicking on the body or any other element without four parents
            try {
                parentClass = document.activeElement.parentElement.parentElement.parentElement.parentElement.className;
            } catch (e) {
                parentClass = '';
            }

            if (parentClass == "panel-editor-toolbar") {
                var editor = $find("<%=reNotePad.ClientID%>"); //get a reference to RadEditor client object
                var doc = editor.get_document(); 
                doc.execCommand("SelectAll", null, false);
                //Collapse selection to the end
                editor.getSelection().collapse();

            } else {
                __doPostBack("", "");
            }
        }
    </script>

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 20 Jan 2022, 07:00 PM

Vessy,

Yes, I tried that method, as I discovered it a few days before you mentioned it.  It did not produce the desired results.  The user still has to manually select inside the content area, then back outside to get the postback to fire.

Just to correct something you mentioned - The exception gets thrown in the TRUE part of the IF statement, and the PostBack gets fired in the FALSE part of the IF statement.  The exception does not stop the postback from occurring. 

So, the exception allows the RadEditor to appear to be "re-selected" after a toolbar button click.  The next time the user clicks outside of the content area, the IF condition will be false, thus firing the postback, and producing the results I need.

The exception is not ideal, and I will continue to look for a better solution. 

I've since changed it to just throw an exception, rather than call a non-existent method:  

throw 'Force Editor Content area selection';

What do you mean by "not propered call of the OnClientInlineEditCompleted event"?



Vessy
Telerik team
commented on 24 Jan 2022, 05:11 PM

Hi Jeff,

By saying  "not proper call of the OnClientInlineEditCompleted event" I meant that the JavaScript error could be the reason for the a broken cycle of the client-side events, resulting in the OnClientInlineEditCompleted event not triggered in the expected moment.

Of course, if the exception brings the target behavior I encourage you to use it. 

I am just pasting below my test setup in case you decide to go in this direction:

        <telerik:RadScriptManager ID="RadScriptManager1" runat="server">
            <Scripts>
                <asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.Core.js" />
                <asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.jQuery.js" />
                <asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.jQueryInclude.js" />
            </Scripts>
        </telerik:RadScriptManager>

        <div>
            <asp:Panel runat="server" ID="ToolbarHolder" CssClass="panel-editor-toolbar">
                <div id="toolbarDiv" class="RadEditor reCustomContainer">
                </div>
            </asp:Panel>
        
        <telerik:RadEditor ID="reNotePad" runat="server" Width="100%" Height="100%" RenderMode="Lightweight"
            ForeColor="SteelBlue" Font-Names="Comic Sans MS" BorderStyle="None" EmptyMessage="Enter your notes here ..."
            OnClientInlineEditCompleted="OnClientInlineEditCompleted"
            EditModes="Design" EditType="Inline" Visible="true" NewLineMode="Br">
            <Content>
        <div style="width: 420px">
            <h2 class="titleText">RadEditor for ASP.NET AJAX</h2>
            <p style="text-align: justify;">
                <span style="color: #4f6128; font-size: 19px;"><strong>RadEditor</strong></span><span style="color: #4f6128;">
                </span>is not simply an HTML
                <a href="#HTMLDescription">
                    <sup>1</sup>
                </a> Editor. It is what Microsoft chose to use in <strong>MSDN</strong>, <strong>CodePlex</strong>, <strong>TechNet</strong>, <strong>MCMS</strong> and even as an alternative to the default editor in
                <a href="https://www.telerik.com/products/aspnet-ajax/sharepoint.aspx">SharePoint</a>.
            </p>
        </div>
            </Content>
            <Tools>
                <telerik:EditorToolGroup dockingzone="toolbarDiv">
                    <telerik:EditorTool Name="Undo" />
                    <telerik:EditorTool Name="Redo" />
                    <telerik:EditorSeparator />
                    <telerik:EditorTool Name="Bold" />
                    <telerik:EditorTool Name="Italic" />
                    <telerik:EditorTool Name="Underline" />
                    <telerik:EditorSeparator />
                    <telerik:EditorTool Name="ForeColor" />
                    <telerik:EditorTool Name="BackColor" />
                    <telerik:EditorSeparator />
                    <telerik:EditorTool Name="InsertOrderedList" />
                    <telerik:EditorTool Name="InsertUnorderedList" />
                    <telerik:EditorSeparator />
                    <telerik:EditorTool Name="InsertHorizontalRule" />
                    <telerik:EditorSeparator />
                    <telerik:EditorTool Name="Indent" />
                    <telerik:EditorTool Name="Outdent" />
                    <telerik:EditorSeparator />
                    <telerik:EditorTool Name="InsertLink" />
                    <telerik:EditorSeparator />
                    <telerik:EditorTool Name="JustifyLeft" />
                    <telerik:EditorTool Name="JustifyCenter" />
                    <telerik:EditorTool Name="JustifyRight" />
                    <telerik:EditorTool Name="JustifyFull" />
                </telerik:EditorToolGroup>
            </Tools>
        </telerik:RadEditor></div>
        <telerik:RadLabel ID="Label1" runat="server"></telerik:RadLabel>
        <script>
            function OnClientInlineEditCompleted() {

                let parentClass;
                // Handle exception thrown when clicking on the body or any other element without four parents
                try {
                    parentClass = document.activeElement.parentElement.parentElement.parentElement.parentElement.className;
                } catch (e) {
                    parentClass = '';
                }
                console.log(parentClass);

                if (parentClass == "panel-editor-toolbar") {
                    var editor = $find("<%=reNotePad.ClientID%>"); //get a reference to RadEditor client object
                    var doc = editor.get_document();
                    doc.execCommand("SelectAll", null, false);
                    //Collapse selection to the end
                    editor.getSelection().collapse();

                } else {
                    __doPostBack("", "");
                }

            }
        </script>
        <telerik:RadTextBox ID="RadTextBox1" runat="server"></telerik:RadTextBox>

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 24 Jan 2022, 05:26 PM

As always, I'm thankful for your assistance.  That being said, and as mentioned in the prior reply, I've implemented this exact setup with no success.  We would choose to go in this direction if it yielded the desired results.

 

Vessy
Telerik team
commented on 26 Jan 2022, 07:39 PM

Thank you for the update, Jeff. I guess in this case the thrown by you exception is the way to go as far as it brings the target result.
Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 27 Jan 2022, 02:40 PM

I'm not very comfortable with sticking with the exception.  It would be nice to understand what is going on when the exception is thrown, that causes the re-selection of the editor - and more importantly why it works for you with your test setup code, and not for me.
Rumen
Telerik team
commented on 01 Feb 2022, 11:11 AM | edited

Hi Jeff, 

Allow me to jump into this thread.

Can you please explain in more detail what do you mean by: 

"That being said, and as mentioned in the prior reply, I've implemented this exact setup with no success." - what has happened and what is not working with this approach? It might be useful to share two Fiddler Jam captures - one with the code Veselina provided in her last reply, and another one showing your current implementation along with videos and instructions what is happening. This way we will be able to compare them, mock and test them on our side and see the problems/errors you get with each approach. 

The Fiddler Jam captures will provide a lot of info easily and allow us to investigate further. Keep in mind that starting from a blank page or at least navigating to your page via the address bar is crucial for capturing all requests and responses:

https://docs.telerik.com/devtools/aspnet-ajax/knowledge-base/common-capture-issues-with-fiddler-jam 

Thank you!

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 01 Feb 2022, 01:25 PM

Rumen,

Feel free to join in the discussion.  I'll summarize what I've posted before:  

When the user clicks a toolbar button, I capture that event, and try to force select/re-select the RadEditor content so that when the next time the user clicks anywhere outside of the content, the OnInlineEditCompleted event fires thus triggering the postback to save data if it has been changed.

The forced thrown exception makes this happen.  For example, the user will select some text, click the bold button, then click outside the content area, firing the postback, saving the changes back to the database.

Without the forced thrown exception, the user follows the same path above, but when they click outside the content area, after clicking a toolbar button, the OnInlineEditCompleted event doesn't fire - if the user simply clicks inside the content area, then immediately outside the content area, the event and postback fire.

I've used the setup Vessy provided, and the results are the same - The user still has to click inside the content area, then back outside to trigger the postback.

I recently downloaded Fiddler and will try to get comfortable with it to provide the info you requested.

Thanks.

 

 

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 14 Feb 2022, 01:51 PM

Rumen,

I've recorded the two Fiddler jams and video you requested.  I'd rather not post them publicly here in this forum.  Which method do you recommend we use to get them to you?

Let me know,

Jeff.

Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
commented on 14 Feb 2022, 06:32 PM

Rumen, 

I've opened a support ticket and provided links to the Fiddler Jams there.  The ticket number is 1553799.

Thanks,

Jeff.

Vessy
Telerik team
commented on 15 Feb 2022, 01:44 PM

Hi Jeff,

I have  just answered your support ticket on the matter. Please, give the suggested approach a try and let me know how it goes.

No answers yet. Maybe you can help?

Tags
Editor Splitter
Asked by
Jeff
Top achievements
Rank 2
Iron
Iron
Veteran
Share this question
or