I have a mvc4 razor view consists of a Kendo mvc grid with detail templates which are also Kendo mvc grids within each tab of a Kendo Tabstrip.
Each detail grids are linked to the master grid via the unique ID of the master grid. All the grids can render without problem when the columns are text.
However, once I starting to customize some columns, i.e. replacing text column by EditorTemplate, then the grids won't render anymore. I used ForeignKeyColumn in some of the columns and they worked but due to the record size of certain columns, I have to use EditorTemplate to customize the source and limit the number of records pass to the client each time.
Here's my code for the view.
@(Html.Kendo().Grid<EMD.DAL.Domain.Attribute.AssetSubType>()
.Name("subTypeGrid")
.Columns(columns =>
{
columns.Bound(c => c.AssetSubTypeID).Hidden();
columns.ForeignKey(c => c.AssetTypeID, (System.Collections.IEnumerable)ViewData["assetTypes"], "AssetTypeID", "Type").Width(200);
columns.Bound(c => c.SubType).Width(300);
columns.Bound(c => c.Description).Width(300);
columns.Bound(c => c.ProductTypeID).Width(100);
columns.Bound(c => c.PhysicalItem).Width(100);
columns.Bound(c => c.LastModified).Hidden();
columns.Bound(c => c.LastModifiedBy).Hidden();
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(180);
})
.
.
.Editable(editable => editable.Mode(GridEditMode.InLine))
.ClientDetailTemplateId("SubTypeChildrenTemplate")
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(p => p.AssetSubTypeID);
})
)
<script id="SubTypeChildrenTemplate" type="text/kendo-tmpl">
@(Html.Kendo().TabStrip()
.Name("tabStrip_#=AssetSubTypeID#")
.SelectedIndex(0)
.Items(tabStrip =>
{
tabStrip.Add().Text("Specs").Content(@<text>
@(Html.Kendo().Grid<EMD.DAL.Domain.Attribute.SubTypeSpec>()
.Name("specGrid_#=AssetSubTypeID#")
.Columns(columns =>
{
columns.ForeignKey(o => o.SubTypeSpecCategoryID, (System.Collections.IEnumerable)ViewData["subTypeSpecsCat"], "SubTypeSpecCategoryID", "SpecCategory").Title("SpecCategory").Width(100);
columns.Bound(o => o.Spec).Width(100);
columns.Bound(o => o.SpecValue).Title("SpecValue").Width(100);
columns.ForeignKey(o => o.UnitID, (System.Collections.IEnumerable)ViewData["specUnits"], "UnitID", "SpecUnit").Width(50).Title("Unit");
columns.Bound(o => o.Comment).Width(100);
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(180);
})
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(p => p.SubTypeSpecID);
})
.Read(read => read.Action("SubTypeSpecs_Read", "AssetAttribute", new { assetSubTypeID = "#=AssetSubTypeID#" }))
.Update(update => update.Action("SubTypeSpecs_Update", "AssetAttribute"))
.Create(update => update.Action("SubTypeSpecs_Create", "AssetAttribute").Data("onAddSubItem"))
.Destroy(update => update.Action("SubTypeSpecs_Destroy", "AssetAttribute"))
)
.
.
.Editable(editable => editable.Mode(GridEditMode.InLine))
.ToClientTemplate()
)
</text>);
tabStrip.Add().Text("Attributes").Content(@<text>
@(Html.Kendo().Grid<EMD.DAL.Domain.Attribute.SubTypeAttribute>()
.Name("attributeGrid_#=AssetSubTypeID#")
.Columns(columns =>
{
columns.ForeignKey(c => c.AttributeValueID, (System.Collections.IEnumerable)ViewData["attributes"], "AttributeValueID", "Attribute").Title("Attribute").Width(200);
columns.Bound(c => c.DefaultValue);
columns.Bound(c => c.Description);
columns.Bound(c => c.LastModified).Hidden();
columns.Bound(c => c.LastModifiedBy).Hidden();
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(180);
})
.
.
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(5)
.Model(model =>
{
model.Id(p => p.SubTypeAttributeID);
model.Field(p => p.SubTypeAttributeID).Editable(false);
model.Field(p => p.LastModified).Editable(false);
model.Field(p => p.LastModifiedBy).Editable(false);
})
.Read(read => read.Action("SubTypeAttributes_Read", "AssetAttribute", new { assetSubTypeID = "#=AssetSubTypeID#" }))
.Create(create => create.Action("SubTypeAttributes_Create", "AssetAttribute").Data("onAddSubItem"))
.Update(update => update.Action("SubTypeAttributes_Update", "AssetAttribute"))
.Destroy(destroy => destroy.Action("SubTypeAttributes_Destroy", "AssetAttribute"))
)
.ToClientTemplate()
)
</text>);
tabStrip.Add().Text("Parts").Content(@<text>
@(Html.Kendo().Grid<EMD.DAL.Domain.Attribute.SubTypePartList>()
.Name("partGrid_#=AssetSubTypeID#")
.Columns(columns =>
{
columns.Bound(c => c.ParentID).Hidden();
columns.Bound(c => c.AssetSubType).Title("SubType").ClientTemplate("\\#=AssetSubType.SubType\\#").EditorTemplateName("SubTypeEditor");
columns.Bound(c => c.SPartID);
columns.Bound(c => c.Qty);
columns.Bound(c => c.Description);
columns.Bound(c => c.InsideParent);
columns.Bound(c => c.LastModified).Hidden();
columns.Bound(c => c.LastModifiedBy).Hidden();
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(180);
})
.
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(p => p.ID);
model.Field(p => p.AssetSubType);
})
.Read(read => read.Action("SubTypePartLists_Read", "AssetAttribute", new { assetSubTypeID = "#=AssetSubTypeID#" }))
.Create(create => create.Action("SubTypePartLists_Create", "AssetAttribute").Data("onAddSubItem"))
.Update(update => update.Action("SubTypePartLists_Update", "AssetAttribute"))
.Destroy(destroy => destroy.Action("SubTypePartLists_Destroy", "AssetAttribute"))
)
.ToClientTemplate()
)
</text>);
tabStrip.Add().Text("Asset Items").Content(@<text>
@(Html.Kendo().Grid<EMD.Manager.ViewModels.AssetItemVM>()
.Name("assetItemsGrid_#=AssetSubTypeID#")
.Columns(columns =>
{
columns.Bound(c => c.Asset);
columns.Bound(c => c.Description);
columns.Bound(c => c.Location).Title("Location").ClientTemplate("\\#=Location.Asset\\#").EditorTemplateName("LocationEditor");
columns.Bound(c => c.Owner);
columns.Bound(c => c.LastModified).Hidden();
columns.Bound(c => c.LastModifiedBy).Hidden();
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(180);
})
.ToolBar(toolbar =>
{
toolbar.Create().HtmlAttributes((new { onclick = "setMasterSubTypeID(this, #=AssetSubTypeID#)" }));
})
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(p => p.AssetItemID);
model.Field(p => p.Location);
})
.Read(read => read.Action("AssetItems_Read", "AssetAttribute", new { assetSubTypeID = "#=AssetSubTypeID#" }))
.Create(create => create.Action("AssetItems_Create", "AssetAttribute").Data("onAddSubItem"))
.Update(update => update.Action("AssetItems_Update", "AssetAttribute"))
.Destroy(destroy => destroy.Action("AssetItems_Destroy", "AssetAttribute"))
)
.ToClientTemplate()
)
</text>);
tabStrip.Add().Text("SubType I/O").Content(@<text>
@(Html.Kendo().Grid<EMD.DAL.Domain.Attribute.SubTypeIO>()
.Name("IOGrid_#=AssetSubTypeID#")
.Columns(columns =>
{
columns.ForeignKey(c => c.IOTypeID, (System.Collections.IEnumerable)ViewData["ioTypes"], "IOTypeID", "IType").Title("I/OType").Width(50);
columns.ForeignKey(c => c.FieldDeviceTypeID, (System.Collections.IEnumerable)ViewData["fieldDevices"], "FieldDeviceTypeID", "FieldDevice").Title("Field Device Type").Width(150);
columns.ForeignKey(c => c.EngUnitID, (System.Collections.IEnumerable)ViewData["engUnits"], "EngUnitID", "EngineeringUnit").Title("Eng Unit").Width(100);
columns.Bound(c => c.IOTag);
columns.Bound(c => c.IODescription);
columns.Bound(c => c.IOModule);
columns.Bound(c => c.IOChannelNo);
columns.Bound(c => c.InputLow);
columns.Bound(c => c.InputHigh);
columns.Bound(c => c.MinEngValue);
columns.Bound(c => c.MaxEngValue);
columns.Bound(c => c.FATOnly);
columns.Bound(c => c.LastModified).Hidden();
columns.Bound(c => c.LastModifiedBy).Hidden();
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(180);
})
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(p => p.SubTypeIOID);
})
.Read(read => read.Action("SubTypeIOs_Read", "AssetAttribute", new { assetSubTypeID = "#=AssetSubTypeID#" }))
.Create(create => create.Action("SubTypeIOs_Create", "AssetAttribute").Data("onAddSubItem"))
.Update(update => update.Action("SubTypeIOs_Update", "AssetAttribute"))
.Destroy(destroy => destroy.Action("SubTypeIOs_Destroy", "AssetAttribute"))
)
.ToolBar(toolbar =>
{
toolbar.Create().HtmlAttributes((new { onclick = "setMasterSubTypeID(this, #=AssetSubTypeID#)" }));
})
.ToClientTemplate()
)
</text>);
})
)
</script>
Here's my two EditorTemplate.
@model object
<script>
function valueMapper(options) {
$.ajax({
url: "@Url.Action("AssetItems_ValueMapper", "AssetAttribute")",
data: convertValues(options.value),
success: function (data) {
options.success(data);
}
});
}
function convertValues(value) {
var data = {};
value = $.isArray(value) ? value : [value];
for (var idx = 0; idx < value.length; idx++) {
data["values[" + idx + "]"] = value[idx];
}
return data;
}
</script>
@(Html.Kendo().DropDownListFor(m => m)
.HtmlAttributes(new { id = "LocationDDL#=AssetSubTypeID#" })
.Name("Location")
.DataTextField("Asset")
.DataValueField("AssetItemID")
//.AutoBind(false)
.Filter(FilterType.StartsWith)
.MinLength(3)
.DataSource(source =>
{
source.Custom()
.ServerFiltering(true)
.ServerPaging(true)
.ServerSorting(true)
.PageSize(5)
.Type("aspnetmvc-ajax")
.Transport(transport =>
{
transport.Read("AssetItemsDropDown_Read", "AssetAttribute");
})
.Schema(schema =>
{
schema.Data("Data").Total("Total");
});
})
//.Events(events => events.Change("selected"))
.Virtual(v => v.ItemHeight(26).ValueMapper("valueMapper"))
)
@model object
<script>
function valueMapper(options) {
$.ajax({
url: "@Url.Action("SubTypes_ValueMapper", "AssetAttribute")",
data: convertValues(options.value),
success: function (data) {
options.success(data);
}
});
}
function convertValues(value) {
var data = {};
value = $.isArray(value) ? value : [value];
for (var idx = 0; idx < value.length; idx++) {
data["values[" + idx + "]"] = value[idx];
}
return data;
}
</script>
@( Html.Kendo().DropDownListFor(m => m)
.HtmlAttributes(new { id = "SubTypeDDL#=AssetSubTypeID#" })
.Name("AssetSubType")
.DataTextField("SubType")
.DataValueField("AssetSubTypeID")
.HtmlAttributes(new { style = "width:300px" })
.Filter(FilterType.StartsWith)
.MinLength(3)
.DataSource(source =>
{
source.Custom()
.ServerFiltering(true)
.ServerPaging(true)
.ServerSorting(true)
.PageSize(5)
.Type("aspnetmvc-ajax")
.Transport(transport =>
{
transport.Read("AssetSubTypesDropDown_Read", "AssetAttribute");
})
.Schema(schema =>
{
schema.Data("Data").Total("Total");
});
})
.Virtual(v => v.ItemHeight(26).ValueMapper("valueMapper"))
//.Events(events => events.Change("selected"))
)
I found the lines causing the problem are both related to using EditorTemplate. The grids load again once I comment these two lines out.
columns.Bound(c => c.AssetSubType).Title("SubType").ClientTemplate("\#=AssetSubType.SubType\#").EditorTemplateName("SubTypeEditor");
columns.Bound(c => c.Location).Title("Location").ClientTemplate("\#=Location.Asset\#").EditorTemplateName("LocationEditor");
According to Kendo documentation, I have escaped the #hash by putting in two (2)\ backslashes (screen only shows one but I put two in the code) before each instance of # but the grids still don't render.
However, if I take out these detail grids and put them on a new view, they will work.
I tried to assign unique name to the DropDownList as well but it doesn't seem to help.
Any help will be greatly appreciated.