Search code examples
c#angularjsasp.net-web-apikendo-uikendo-scheduler

What's wrong with update & destroy entities in Kendo scheduler


I was trying to use Kendo scheduler with a bundle of ASP.NET MVC Web API. Client side performed as Angular JS application. Server side: for read I'm using odata controller for create/update/delete actions Web API controller.

I have three issues with configuration of scheduler:

  1. When I try to send model for create & update it will not send one model, but send a bundle of it

    {"models":[{"Id":0,"Title":"No title","StartDate":"2015-04-28T11:00:00.000Z","EndDate":"2015-04-28T11:30:00.000Z","StartTimezone":"","EndTimezone":"","Description":"","RecurrenceID":0,"RecurrenceRule":"","RecurrenceException":"","IsAllDay":false,"OwnerID":0},{"Id":0,"Title":"No title","StartDate":"2015-04-28T13:00:00.000Z","EndDate":"2015-04-28T13:30:00.000Z","StartTimezone":"","EndTimezone":"","Description":"","RecurrenceID":0,"RecurrenceRule":"","RecurrenceException":"","IsAllDay":false,"OwnerID":0}]}

  2. My update method send data to "api/Schedule/CreateEvent", instead of correct way "api/Schedule/UpdateEvent"

  3. My delete method send data to "api/Schedule/CreateEvent", instead of correct way "api/Schedule/DeleteEvent/"

Is anybody can help me?

Angular Code:

$scope.schedulerOptions = {
                date: new Date("2015/04/28"),
                dateHeaderTemplate: kendo.template("<strong>#=kendo.toString(date, 'd/M')#</strong>"),
                height: 600,
                views: [
                    //"day",
                    {
                        type: "workWeek",
                        selected: true,
                    },
                    //"week",
                    //"month",
                ],
                timezone: "Etc/UTC",
                dataSource: {
                    batch: true,
                    type: 'odata',
                    transport: {
                        read: {
                            url: "odata/ScheduleOData",
                            dataType: "json",
                            contentType: "application/json; charset=utf-8",
                        },
                        update: {
                            url: "api/Schedule/UpdateEvent",
                            type: "Post",
                            dataType: "json",
                            contentType: "application/json; charset=utf-8",
                        },
                        create: {
                            url: "api/Schedule/CreateEvent",
                            type: "Post",
                            dataType: "json",
                            contentType: "application/json; charset=utf-8",
                        },
                        destroy: {
                            url: function (data) {
                                return "api/Schedule/DeleteEvent/" + data.Id;
                            },
                            type: "Delete",
                            dataType: "json",
                            contentType: "application/json; charset=utf-8",
                        },
                        //parameterMap: function (data, operation) {
                        //    return JSON.stringify(data);
                        //}
                        parameterMap: function (data, operation) {
                            if (operation == "destroy") {
                                return;// kendo.stringify(data);
                            }
                            var d = kendo.data.transports.odata.parameterMap(data, operation);
                            delete d.$inlinecount; // <-- remove inlinecount parameter    
                            delete d.$callback;
                            return d;
                        }
                    },
                    schema: {
                        model: {
                            id: "Id",
                            fields: {
                                taskId: { from: "Id", type: "number" },
                                title: { from: "Title", defaultValue: "No title", validation: { required: true } },
                                start: { type: "date", from: "StartDate" },
                                end: { type: "date", from: "EndDate" },
                                startTimezone: { from: "StartTimezone" },
                                endTimezone: { from: "EndTimezone" },
                                description: { from: "Description" },
                                recurrenceId: { from: "RecurrenceID", defaultValue: 0 },
                                recurrenceRule: { from: "RecurrenceRule" },
                                recurrenceException: { from: "RecurrenceException" },
                                isAllDay: { type: "boolean", from: "IsAllDay" },
                                ownerId: { from: "OwnerID", defaultValue: 0 }
                            }
                        },
                        data: function (response) {
                            return response['value'];
                        },
                        total: function (response) {
                            return response['odata.count'];
                        }

                    }
                }
            };

Web API Code:

public class ScheduleController : ApiController {
        private readonly ISubjectsService _subjectsService;
        private readonly IGenericService _genericService;
        private readonly IMembershipService membership;
        private readonly IMappingEngine mapper;

        public ScheduleController(ISubjectsService subjectsService, IGenericService igs, IMappingEngine mapper, IMembershipService membership) {
            this._subjectsService = subjectsService;
            this._genericService = igs;
            this.mapper = mapper;
            this.membership = membership;
        }

        public void UpdateEvent(RootObject model) {
            // some logic
        }

        public void CreateEvent(RootObject model) {
            // some logic
        }

        [HttpDelete]
        public void DeleteEvent(int key) {
            // some logic
        }
    }

Solution

  • The reason multiple models get sent is probably because the datasource's batch mode is set to true; if you change this

     batch: true,
    

    to this

     batch: false,
    

    it should send the creates/updates individually (see here for details)

    I'm not sure it's what you need, but if it's the case that you want to send a single model that contains an array of sub-models for example, you can do something like this:

     parameterMap: function (data, operation) {
    
       if (operation=="create" || operation=="update"){
          var rootModel = {rootProperty:"foo",models:[]};
           data.models.forEach(function(model)){
               //do whatever transformation of the individual models here
               //and add to the aggregate model.
               rootModel.models.push(model);
           }
           return rootModel; //whatever you return from parameterMap is what will be sent in the HTTP request.
         }
         //rest of your special operation cases here                     
      }
    

    In that case you probably do want to keep batch:true.

    As for the other issues - more information is needed, see the comments I posted - you might be better off with a separate question for these :)