Kendo Grid model with an IEnumerable property not updating correctly after Create/Update when using AJAX binding

10,254

So In case anyone stumbles on this in the future, I contacted Telerik support, who explained to me that:

The dataSource supports only value types and will not serialize the arrays in the format that is expected by the model binder.

They also provided me with a workaround using the request Data function to call a JavaScript function which converts the data into the correct format.

In the view, modify the request functions by specifying the name of the JavaScript function to call:

.Create(create => create.Action("AddNote", "ReleaseNotes").Data("serialize"))

And then add in the functions which will do the conversion:

function serialize(data) {
    for (var property in data) {
        if ($.isArray(data[property])) {
            serializeArray(property, data[property], data);
        }
    }
}
function serializeArray(prefix, array, result) {
    for (var i = 0; i < array.length; i++) {
        for (var property in array[i]) {
            result[prefix + "[" + i + "]." + property] = array[i][property];
        }
    }
}
Share:
10,254
Alejo
Author by

Alejo

Updated on June 28, 2022

Comments

  • Alejo
    Alejo almost 2 years

    I'm having a problem where a property of my model is not being correctly updated when sending it to my controller for an Update or Create call from a Kendo Grid. The model looks like this:

    public class ReleaseNotesModel
    {
        public int NoteID { get; set; }
        public int ReleaseID { get; set; }
        public List<TranslationModel> ReleaseNoteTranslations { get; set; }
        public ReleaseNoteType ItemType { get; set; }
    }
    public class TranslationModel
    {
        public int TranslationID { get; set; }
        public string Translation { get; set; }
        public int LanguageID { get; set; }
        public int ItemID { get; set; }
    }
    

    Here is the grid in my view:

    @(Html.Kendo().Grid<ReleaseNotesModel>()
        .Name("Grid")
        .Columns(columns =>
        {
            columns.Bound(m => m.ItemType).Width(140);
            columns.Bound(m => m.Description);
            columns.Command(command =>
                {
                    command.Edit();
                    command.Destroy();
                }).Width(170);
        })
        .ToolBar(toolbar => toolbar.Create())
        .Editable(editable => editable
            .Mode(GridEditMode.PopUp)
            .TemplateName("ReleaseNoteTemplate")
            .Window(w => w.Width(620))
            .DisplayDeleteConfirmation(true)
        )
        .Pageable()
        .Sortable()
        .Scrollable()
        .Filterable()
        .DataSource(dataSource => dataSource
            .Ajax()
            .ServerOperation(false)
            //.Server()
            .Events(e => e.Error("grid_error"))
            .Model(model =>
            {
                model.Id(m => m.NoteID);
                model.Field(m => m.ReleaseID).DefaultValue(Model.ReleaseID);
                model.Field(m => m.ItemType).DefaultValue(ReleaseNoteType.NewFeature);
                //defaultTranslationsList is a List<TranslationModel> with two empty objects in it
                model.Field(m => m.ReleaseNoteTranslations).DefaultValue(defaultTranslationsList);
            })
            .PageSize(5)
            .Read(read => read.Action("GetNotes", "ReleaseNotes", new { releaseID = Model.ReleaseID }))
            .Create(create => create.Action("AddNote", "ReleaseNotes"))
            .Update(update => update.Action("EditNote", "ReleaseNotes"))
            .Destroy(destroy => destroy.Action("DeleteNote", "ReleaseNotes"))
        )
    )
    

    So more specifically, the problem I am having is that in my controller action:

    public async Task<ActionResult> EditNote(ReleaseNotesModel model)
    

    model.ReleaseNoteTranslations always contains two empty objects (properties are null or 0), i.e. the default value which I set for this property. If I set no default value, then I won't have any fields to edit for this property in the popup editor. All the other properties are updated as expected.

    What bugs me is that if I use server binding instead of AJAX, then all the data is correctly received. So I decided to check out the data in the request headers being sent in both cases:

    // Using server binding
    ReleaseID:300
    NoteID:886
    ItemType:1
    ReleaseNoteTranslations[0].ItemID:886
    ReleaseNoteTranslations[0].LanguageID:1
    ReleaseNoteTranslations[0].TranslationID:869
    ReleaseNoteTranslations[0].Translation:The module is now released!
    ReleaseNoteTranslations[1].ItemID:886
    ReleaseNoteTranslations[1].LanguageID:2
    ReleaseNoteTranslations[1].TranslationID:870
    ReleaseNoteTranslations[1].Translation:Le module est maintenant disponible!
    NoteID:886
    
    // Using AJAX binding
    sort:
    group:
    filter:
    NoteID:886
    ReleaseID:300
    ReleaseNoteTranslations[0][TranslationID]:869
    ReleaseNoteTranslations[0][Translation]:The module is now released!
    ReleaseNoteTranslations[0][LanguageID]:1
    ReleaseNoteTranslations[0][ItemID]:886
    ReleaseNoteTranslations[1][TranslationID]:870
    ReleaseNoteTranslations[1][Translation]:Le module est maintenant disponible!
    ReleaseNoteTranslations[1][LanguageID]:2
    ReleaseNoteTranslations[1][ItemID]:886
    ItemType:1
    

    Now what I notice first here is the syntax of objectName[index].PropertyName vs objectName[index][PropertyName]

    I wonder if this could be the cause of my problem, and if so, is there a way for me to go and directly manipulate the data being sent to fix it? Could this be a bug in the way Kendo Grid sends data through Ajax binding?

    Either way, any help would be much appreciated!