I have the following dilemma:
I am trying to make a Kendo UI Grid inside a partial View that will be used with different types of objects and that can support actions such as Delete or Create.
The object looks like this:
public class GridViewModel
{
public Type ObjectType { get; set; }
public IEnumerable<object> Items { get; set; }
public GridViewModel(Type type, IEnumerable<object> items)
{
Items = items;
ObjectType = type;
}
}
ObjectType is a variable of type Type that retains the type of a class. For example Employee, Product, Invoice or anything.
Items is an IEnumerable list of objects of the type previously mentioned.
Lets say we have an Employee View and we call inside the following:
@model IEnumerable<Employee>
@{
GridViewModel gridModel = new GridViewModel(typeof(Employee), Model);
}
@{
Html.RenderPartial("_AdvancedGrid", gridModel);
}
This way we load a partial view with the specified object as model.
Now the Kendo UI Grid inside the partial view:
@model XMLProject.Models.GridViewModel
@{
System.Reflection.PropertyInfo[] propertyArray = Model.ObjectType.GetProperties();
}
@(Html.Kendo().Grid<Employee>()
.Name("Grid")
.Columns(columns =>
{
foreach (var property in propertyArray)
{
columns.Bound(property.Name);
}
columns.Command(c => c.Destroy());
})
.ToolBar(toolbar => toolbar.Create())
.Groupable()
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id("Id"))
.Destroy(update => update.Action("Delete", "Products"))
.Read(read => read.Action(ViewBag.PageLayout.ReadDataActionName, ViewBag.PageLayout.ControllerName))
.Update(update => update.Action("Products_Update", "Home"))
.Create(create => create.Action("Products_Create", "Home"))
)
)
As you can see I am using Grid < Employee >.
But this is incorrect as I want to use Grid<'any type of object'>, but the syntax will not let me give it a string and then change it to class type. I tried things like:
Html.Kendo().Grid<(Type)Model.ObjectType>
Html.Kendo().Grid<typeof(Model.ObjectType)>
... and other stupid ways.
My final question is whether I can somehow trick the compiler into seeing a string or something like that as a Class from the project.
I also tried something like:
Html.Kendo().Grid<IProduct>
This kinda works, but it means that ANY object that I want to use in a grid MUST have all the fields of the Product interface.
As a final observation, I made this work, but without implementing any Delete/ Create / Update actions built into the grid by using a different syntax like:
@(Html.Kendo().Grid(Model.Items)
.Name("Grid")
.Columns(columns =>
{
foreach (var property in propertyArray)
{
columns.Bound(property.Name);
}
})
.Groupable()
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action(ViewBag.PageLayout.ReadDataActionName, ViewBag.PageLayout.ControllerName))
)
)
UPDATE:
I found a solution.
@model GridViewModel
@using Kendo.Mvc.UI;
@{
System.Reflection.PropertyInfo[] propertyArray = Model.ObjectType.GetProperties();
List<object> mockList = new List<object>();
}
@(Html.Kendo().Grid(mockList)
.Name("Grid")
.Columns(columns =>
{
foreach (var property in propertyArray)
{
columns.Bound(property.Name);
}
columns.Command(c => c.Custom("Delete").Click("kendoGrid.onDeleteButtonClicked"));
columns.Command(c => c.Custom("Edit").Click("kendoGrid.onEditButtonClicked"));
})
.Groupable()
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action(Model.ReadDataActionName, ViewBag.PageLayout.ControllerName))
)
)
What I did was to get rid of all the useless standard function like Destroy or Create provided by Kendo because they required the synthax with Grid < 'object type' >.
The GridViewModel object now looks like this :
public class GridViewModel
{
public Type ObjectType { get; set; }
public string ReadDataActionName { get; set; }
public GridViewModel(Type type, string actionName)
{
ObjectType = type;
ReadDataActionName = actionName;
}
}
where ReadDataActionName is the action name responsible for returning a list of Json objects that the Kendo grid can read.
Then I made custom commands that point to custom functions made in Jquery that sends as a parameter a pretty complex object that has (besides all other things) the Json object from the grid that I clicked on.
The esential thing in the end is the .Read function in the Datasource. That must point to a function that returns a special type of Json (go see the Kendo documentation for type of Json your action must return on their demos examples).
So then you don't need an array of objects as you've seen:
@(Html.Kendo().Grid(mockList)
...
)
where mocklist is a list of objects (empty and lonely - just to trick the function that won't work otherwise).
And the FINAL result is that I have a general grid that accepts any array of Objects with Delete and Edit buttons that point to functions that one can customize based on his preferences - it can open a pop-up with data from a partial view, a full view or anything you want. I even customized a delete function to make a delete Ajax post without any confirmation required from the user and it totally works.