First off, this is my very first...ever...!
When updating data(inline) in the grid, Delete is routing to the Create function. When I create (the first record), it is created correctly. When I try to add another record, two records are added: the record I am creating and a duplicate of the original record. It appears to be looping through the data in the grid and adding/duplicating each record every time.
Even when I try to delete, the records are duplicated in the table again
I have verified that the ID of the table (which is a mapping table) is included as model.Id(c => c.Id) and even tried adding a hidden field for the Id.
More background, I have two embedded dropdown lists that are set using the templates. The data is loaded when the template is because the data in the dropdown is dependent on the records in the current grid. I don't want the user to create multiple records for the same custom field.
Here is the grid, that is rendered in a modal window via a partial view:
@(Html.Kendo().Grid<Web.Models.Activity.ActivityCustomFieldModel>
()
.Name("CustomMapping-grid")
.HtmlAttributes(new { style = "height: 250px;" })
.Columns(columns =>
{
columns.Bound(p => p.Id).Hidden(true);
columns.Bound(p => p.CustomFieldId)
.Title("Custom Field")
.HeaderHtmlAttributes(new { style = "font-weight: bold" })
.EditorTemplateName("CustomFieldListDD")
.ClientTemplate("#:CustomFieldName#");
columns.Bound(p => p.ComponentTypeId)
.Title("Component Type")
.HeaderHtmlAttributes(new { style = "font-weight: bold" })
.EditorTemplateName("ComponentListDD")
.ClientTemplate("#:ComponentTypeName#");
columns.Bound(p => p.IsRequired)
.Title("Required")
.HeaderHtmlAttributes(new { style = "font-weight: bold; text-align: center" })
.HtmlAttributes(new { style = "text-align: center" })
.Width(60)
.ClientTemplate(reqdTemplate);
columns.Bound(p => p.IsActive)
.Title("Active")
.HeaderHtmlAttributes(new { style = "font-weight: bold; text-align: center" })
.HtmlAttributes(new { style = "text-align: center" })
.Width(60)
.ClientTemplate(statusTemplate);
columns.Command(command =>
{
command.Edit().Text(" ").UpdateText(" ").CancelText(" ");
command.Destroy().Text(" ");
})
.HeaderHtmlAttributes(new { style = "text-align: center; font-weight: bold" })
.HtmlAttributes(new { style = "text-align: center" })
.Title("Action");
})
.Scrollable(scr => scr.Height("auto"))
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource
.Ajax()
.Events(dsevents => dsevents.Error("error_handler")
.RequestEnd("ReloadGrid"))
.Model(model =>
{
model.Id(c => c.Id);
})
.Read(read => read.Action("CustomFieldMap_Read", "Activity").Data("getActivityInfo"))
.Create(create => create.Action("CustomFieldMap_Create", "Activity").Data("getActivityInfo"))
.Update(update => update.Action("CustomFieldMap_Update", "Activity"))
.Destroy(destroy => destroy.Action("CustomFieldMap_Destroy", "Activity"))
)
.Events(gridevents => gridevents.Save("CustomFieldMap_Save"))
)
Here is the javascript to get the needed data back to the controller
function getActivityInfo(e) {
console.log("get mapping parent data")
var data = {
SearchId: $("#DivisionId").val(),
SearchParentId: $('#ParentId').val()
};
return data;
}
function CustomFieldMap_Save(e) {
console.log("update cust and comp Id values.")
var customFieldId = $("#CustomFieldId_CustomFieldId").data("kendoDropDownList").value();
var componentTypeId = $("#ComponentTypeId_ComponentTypeId").data("kendoDropDownList").value();
e.model.set("CustomFieldId", customFieldId);
e.model.set("ComponentTypeId", componentTypeId);
}
Along with the controller code
public IActionResult CustomFieldMap_Read([DataSourceRequest] DataSourceRequest request, DivisionSearchModel model)
{
// get the Custom field mappings for the parentId value in the DivisionSearchModel
var mappings = _activityCustomFieldService.GetCustomFieldMappingsforActivity(model.SearchParentId);
var gridModel = new DataSourceResult
{
Data = mappings.Select(x =>
{
var dataModel = _mapper.Map<ActivityCustomFieldModel>(x);
dataModel.CustomFieldName = x.CustomField.Name;
return dataModel;
}),
Total = mappings.Count()
};
return Json(gridModel);
}
[HttpPost]
public IActionResult CustomFieldMap_Create([DataSourceRequest] DataSourceRequest request, ActivityCustomFieldModel model, DivisionSearchModel parent)
{
if (ModelState.IsValid)
{
model.ActivityId = parent.SearchParentId;
var newMapping = _mapper.Map<ActivityCustomField>(model);
_activityCustomFieldRepository.Insert(newMapping);
model.Id = newMapping.Id;
}
return Json(new[] { model }.ToDataSourceResult(request, ModelState));
}
[HttpPost]
public IActionResult CustomFieldMap_Update([DataSourceRequest] DataSourceRequest request, ActivityCustomFieldModel model)
{
if (ModelState.IsValid)
{
_activityCustomFieldService.Update(_mapper.Map<ActivityCustomField>(model));
}
return Json(new[] { model }.ToDataSourceResult(request, ModelState));
}
[HttpDelete]
public IActionResult CustomFieldMap_Destroy([DataSourceRequest] DataSourceRequest request, ActivityCustomFieldModel model)
{
_activityCustomFieldRepository.Delete(_mapper.Map<ActivityCustomField>(model));
return Json(new[] { model }.ToDataSourceResult(request, ModelState));
}
#endregion
#region Utilities
public IActionResult GetCustomFields([DataSourceRequest] DataSourceRequest request, DivisionSearchModel model)
{
var AllCustomFields = _customFieldService.GetAllCustomFields(model.SearchId, true);
var ActivityCustomFields = _activityService.GetCustomFieldsByActivityId(model.SearchParentId);
var customFields = AllCustomFields.Except(ActivityCustomFields).Select(c => new { fieldId = c.Id, fieldName = c.Name }).ToList(); ;
return Json(customFields);
}
And just for grins, this is the dropdownlist template code
@(Html.Kendo().DropDownList()
.Name("CustomFieldId")
.OptionLabel("-- Custom Field --")
.DataTextField("fieldName")
.DataValueField("fieldId")
.HtmlAttributes(new { style = "width: 100%" })
.DataSource(dataSource => dataSource
.Read(read => read.Action("GetCustomFields", "Activity").Data("getActivityInfo"))
)
)
I have looked and searched for hours and I am sure it will be something simple... I just don't see it.
Change the
HttpDeleteattribute toHttpPost. All Kendo UI client side methods use POST.