Kendo Editor in a Grid Popup Editor

15 posts, 0 answers
  1. Travis
    Travis avatar
    2 posts
    Member since:
    May 2014

    Posted 06 Jul 2015 Link to this post

    In the Kendo Editor documentation it says the following:

    The editor value will be posted as a string and mapped to a variable with the name of the widget. Note that the posted value is HTML-encoded by default, in order to circumvent the ASP.NET request validation. In order to decode the value, use the HttpUtility.HtmlDecode method. (http://docs.telerik.com/kendo-ui/aspnet-mvc/helpers/editor/overview)

     This works fine when I place the editor in a normal view such as Edit.cshtml; however, when I use a Grid and provide a custom popup editor template, I cannot use a Kendo Editor without specifying [AllowHtml] on the model. Why is this?

  2. Alexander Popov
    Admin
    Alexander Popov avatar
    1433 posts

    Posted 08 Jul 2015 Link to this post

    Hi Travis,

    The AllowHtml is required because of the validation that happens during the Model binding. Allowing HTML should be done carefully and per-field as otherwise the application might become vulnerable to XSS attacks.

    Regards,
    Alexander Popov
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. Travis
    Travis avatar
    2 posts
    Member since:
    May 2014

    Posted 08 Jul 2015 in reply to Alexander Popov Link to this post

    I understand why it is required in general. I asked why it's required when used in a Grid popup window but it's not required when using anywhere else. Look at your own documentation. Your documentation says you encode the content before sending to the server so that you don't have to add [AllowHtml]. I created a small proof of concept and I was able to add an editor to a page and post it to a controller action without adding [AllowHtml] to the model. I do the same exact thing as part of a popup editor in a grid and now I have to add [AllowHtml]. I'm just trying to understand why your code is inconsistent.

  4. Alexander Popov
    Admin
    Alexander Popov avatar
    1433 posts

    Posted 10 Jul 2015 Link to this post

    Hello again Travis,

    The encoded option determines whether or not the Editor's textarea is encoded, for example: 
    editor.options.encoded
    true
    editor.element.val()
    "Aniseed <strong>Syrup</strong>"

    editor.options.encoded
    false
    editor.element.val()
    "Aniseed <strong>Syrup</strong>"

    It does not affect the widget value though and the Grid's dataItem is actually updated with values containing HTML strings, which are considered unsafe.

    Regards,
    Alexander Popov
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  5. Leo
    Leo avatar
    15 posts
    Member since:
    Jan 2016

    Posted 27 Mar in reply to Alexander Popov Link to this post

    I know this is an old thread, but as i have the same issue as Travis i don't understand the answer from Alexander.

    I like to use a rich text editor in a grid in inline mode, without the use of AllowHtml, because that would be potentially dangerous.
    Could you help me out?


  6. Niko
    Admin
    Niko avatar
    404 posts

    Posted 29 Mar Link to this post

    Hello Leo,

    Please, check the following help article with a suggestion how to integrate the Kendo Editor as an inline editor in a grid - http://docs.telerik.com/aspnet-mvc/helpers/editor/how-to/inline-editor-in-editor-template.

    Please, note that you may also need to further encode the value of the Editor before assigning it to the hidden input. You could use the kendo.ui.editor.Dom.encode method or any other method that could encode HTML content. This way you will make sure that the value in the model does not contain HTML and thus will not need the AllowHtml attribute.

    Hope this helps.

    Regards,
    Niko
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  7. Leo
    Leo avatar
    15 posts
    Member since:
    Jan 2016

    Posted 30 Mar in reply to Niko Link to this post

    That did do something. But it isn't perfect yet. The editor looks like:

    @model string
     
    @(Html.Kendo().EditorFor(model => model)
        .Name(Html.NameFor(model => model) + "_Editor")
        .Events(events => events.Change(@"function (ev){
        var hiddenInput =  $('#" + Html.NameFor(model => model) + @"');
        hiddenInput.val(htmlEncode(ev.sender.value()));
        hiddenInput.change();
    }"))
    )
     
    @Html.HiddenFor(model => model)

    And the grid has:
    columns.Bound(c => c.Tekst).Encoded(false).EditorTemplateName("RichEditor");

    Now when the grid loads, all is fine.
    1.When in Edit mode the editorbox is empty, while the column contains data.
    2.When saved, the gridrow is showing html tags instead of interpreting them.

    The second problem could be fixed by the update method in the controller returning a non-encoded normal html string. But what about the first problem?

     

    Somehow all this feels a bit sluggish. I would have expected the telerik grid update function to encode strings before sending it to the controller like Travis suggested. In the mean while, if the problem above is fixed it is a gooed workaround for now.

  8. Niko
    Admin
    Niko avatar
    404 posts

    Posted 30 Mar Link to this post

    Hello Leo,

    I suspect that you are not using server-side data binding. In such a case you could add a data-bind attribute to the editor so that the data items collected over an ajax request in the DataSource can be bound to the UI components (Editor in our case):

    @model string
     
    @(Html.Kendo().EditorFor(model => model)
        .Name(Html.NameFor(model => model) + "_Editor")
        .Tag("div")
        .HtmlAttributes(new { data_bind = "value: Tekst" })
        .Tools(tools => tools.Clear().Bold().Italic().Underline())
        .Events(events => events.Change(@"function (ev){
        var hiddenInput =  $('#" + Html.NameFor(model => model) + @"');
        hiddenInput.val(ev.sender.value());
        hiddenInput.change();
    }"))
    )
     
    @Html.HiddenFor(model => model)

    This way the Editor widget in the column editor will be bound to the Tekst property of the data item using the Kendo MVVM framework. In case you need a different name you could send the name through the ViewData of the EditorTemplate:

    columns.Bound(c => c.Tekst).Encoded(false).EditorTemplateName("RichEditor").EditorViewData(new { fieldName = "Tekst" });

    And then use the value in the EditorTemplate through ViewData["fieldName"].

    Hope this helps in resolving the problem.

    Regards,
    Niko
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  9. Leo
    Leo avatar
    15 posts
    Member since:
    Jan 2016

    Posted 03 Apr in reply to Niko Link to this post

    It's still not 100% fixed. I really don't understand why this scenario is so difficult to achieve, i would think many use cases would use the richtext editor inside a grid.

    The final problem is that whenever you change the text and click outside the editor, it updates the hidden field, which updates the editor (default MVVM behaviour) and it gets double encoded. Somehow i can't seem to get this working. Could you provide a working example? Sorry to keep you asking these questions.

    I would like that the column and the editor both have the same point of view where html is interpreted, with no html tag visible to the user and without the use of allowhtml attribute on the model.

  10. Niko
    Admin
    Niko avatar
    404 posts

    Posted 04 Apr Link to this post

    Hello Leo,

    Indeed implementing a solution that avoids the AllowHtml is tricky.

    I believe I should explain a bit more why in this scenario a single Editor on page works as expected and editor in inline grid editing does not.

    Let's start with the plain Editor. A model field is bound directly to the editor widget through the MVC wrapper. Assuming we are using the classic mode of the Editor, the textarea that has been transformed into the widget holds the value of the editor. In the case that the editor has encoded true, the HTML content of the editor is encoded and the string is set as value to the textarea. Submitting the form will submit the content of the textarea, which is already encoded.

    In the inline grid's editor, the editor widget is bound to the grid's model through the Kendo MVVM framework. The data-bind="value: FieldName" attribute binds the model's FieldName with the value() method of the Editor. This method does not encode the HTML content, which means that the model is always updated with HTML content that is not encoded. As a result we need the AllowHtml attribute to designate the specific property to allow HTML and not cause validation error.

    If you find it important to update the behavior of the Editor's value method, then, please, submit a feature request to our uservoice feedback portal.

    Still it is possible currently to come up with an approach that works as expected without the need of AllowHtml. Here is the full code of the editor template:

    @model string
     
    @(Html.Kendo().EditorFor(model => model)
        .Name(Html.NameFor(model => model) + "_Editor")
        .Tag("div")
        .Encode(false)
        .Tools(tools => tools.Clear().Bold().Italic().Underline())
        .Events(events => events.Change(@"function (ev){
        var hiddenInput =  $('#" + Html.NameFor(model => model) + @"');
        var value = kendo.htmlEncode(ev.sender.value());
        hiddenInput.val(value);
        hiddenInput.change();
    }"))
    )
     
    @Html.HiddenFor(model => model)
     
    <script>
        function decodeEntities(encodedString) {
            var textArea = document.createElement('textarea');
            textArea.innerHTML = encodedString;
            return textArea.value;
        }
     
        var hidden = $("#@Html.NameFor(m => m)");
        var e = $("#@Html.NameFor(m => m)_Editor").getKendoEditor();
        hidden.one("change", function () {
            e.value(decodeEntities(hidden.val()));
        })
    </script>

    Please, note that this editor may not be perfect or serve all use-cases. However for the specific case I guess it should work as expected.

    Give it a try and let me know of the outcome. Please, don't forget to send us a feature request in the uservoice about the inline editing in the grid using the editor widget.

    Regards,
    Niko
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  11. Leo
    Leo avatar
    15 posts
    Member since:
    Jan 2016

    Posted 04 Apr in reply to Niko Link to this post

    Hi Niko, Thanks for the reply. Unfortunately i see no difference with the previous attempt.

    When i add a row, add some text, set it to bold and then press save button (or anywhere else outside the editor) the nice looking text is changed to:
    <strong>some text</strong>

    After that it is saved, showing: <strong>some text</strong> in the grid row. After i refresh the grid. It is shown as expected.

  12. Leo
    Leo avatar
    15 posts
    Member since:
    Jan 2016

    Posted 04 Apr in reply to Leo Link to this post

    While i would really like a workaround, i added a uservoice item here: http://kendoui-feedback.telerik.com/forums/127393-kendo-ui-feedback/suggestions/18826615-improve-security-and-support-for-editor-widget-ins

     

  13. Niko
    Admin
    Niko avatar
    404 posts

    Posted 04 Apr Link to this post

    Hello Leo,

    Thank you for posting in the feedback - I appreciate it.

    The problem that you are facing now it that you have encoded HTML in the Model. Adding it directly as content in the Grid will result in seeing the tags, not the rendered content. You could use a ClientTemplate to change the visualized content in the cell:

    .ClientTemplate("#= decodeEntities(Name) #")

    Make sure that decodeEntities method is publicly accessible.

    Also now you should always serve encoded content from the server. The client template will decode the HTML content.

    I added a small fix to the editor's sample - setTimeout is a more consistent approach to waiting for the hidden input to be updated:

    @model string
     
    @(Html.Kendo().EditorFor(model => model)
        .Name(Html.NameFor(model => model) + "_Editor")
        .Tag("div")
        .Encode(false)
        .Tools(tools => tools.Clear().Bold().Italic().Underline())
        .Events(events => events.Change(@"function (ev){
        var hiddenInput =  $('#" + Html.NameFor(model => model) + @"');
        var value = kendo.htmlEncode(ev.sender.value());
        hiddenInput.val(value);
        hiddenInput.change();
    }"))
    )
     
    @Html.HiddenFor(model => model)
     
    <script>
        var hidden = $("#@Html.NameFor(m => m)");
        var e = $("#@Html.NameFor(m => m)_Editor").getKendoEditor();
        setTimeout(function() { e.value(decodeEntities(hidden.val())); })
    </script>

     

    Regards,
    Niko
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  14. Leo
    Leo avatar
    15 posts
    Member since:
    Jan 2016

    Posted 04 Apr in reply to Niko Link to this post

    It takes some iterations, but we are getting close :-)

    The clienttemplate is doing its job perfect, the timeout is not. I think it is on the wrong place (it should be in the change event of the editor) and it's missing an argument, but more important a timeout would never work.
    Whenever you click outside the editor, the timeout is started, then there are two conditions: 
    1. if you update the record before the timeout has passed, the plain html is send to the controller, resulting in an exception
    2. if you wait until the timeout has passed, the editor shows: <strong> some tekst</strong>

     

    And the .HtmlAttributes(new { data_bind = "value: Tekst" }) was missing in the example. What i made so far:

    @model string
     
    @(Html.Kendo().EditorFor(model => model)
    .Name(Html.NameFor(model => model) + "_Editor")
    .HtmlAttributes(new { data_bind = "value: Tekst" })
    .Encode(false)
    .Events(events => events.Change(@"function (ev){
        var hiddenInput =  $('#" + Html.NameFor(model => model) + @"');
        var value = kendo.htmlEncode(ev.sender.value());
        hiddenInput.val(value);
        hiddenInput.change();
    }"))
    )
     
    @Html.HiddenFor(model => model)
     
    <script>
        var hidden = $("#@Html.NameFor(m => m)");
        var e = $("#@Html.NameFor(m => m)_Editor").getKendoEditor();
        e.value(decodeEntities(hidden.val()));
    </script>

  15. Leo
    Leo avatar
    15 posts
    Member since:
    Jan 2016

    Posted 04 Apr in reply to Leo Link to this post

    I after some fiddling, i understand what you try to do with the timeout. It's purpose is to wait for the hidden input to be bound, and not to be updated from the editor. It's also good to note that the previously suggested data_bind = "value: Tekst" is not needed and i can only set the value if the .Tag("div)" is added to the widget:

    Final version workaround:

    view:

    columns.Bound(c => c.Tekst).Encoded(false).ClientTemplate("#= decodeEntities(Tekst) #").EditorTemplateName("RichEditor");

    model:
    entity -> model
    Tekst = HttpUtility.HtmlDecode(entity.Tekst) 

    entity <- model
    no encoding just put it in store after validation (don't forget about script tag)

    editortemplate:

    @model string
     
    @(Html.Kendo().Editor()
    .Name(Html.NameFor(model => model) + "_Editor")
    .Tag("div")
    .Encode(false)
    .Events(events => events.Change(@"function (ev){
        var hiddenInput =  $('#" + Html.NameFor(model => model) + @"');
        var value = kendo.htmlEncode(ev.sender.value());
        hiddenInput.val(value);
        hiddenInput.change();
    }"))
    )
     
    @Html.HiddenFor(model => model)
     
    <script type="text/javascript">
        $(document).ready(function () {
           setTimeout(function () {
                var editor = $("#@Html.NameFor(model => model)_Editor").data("kendoEditor");
                editor.value($("#@Html.NameFor(m => m)").val());
            });
        });
    </script>


Back to Top