My problem is that the grid won't render. The JSON content coming back appears valid to me. I've got a similar grid in DataTables where I've got the grid to at least render the first level but this one is proving to be stubborn. I'd prefer to use KendoUI if possible.
I've determined the the Ajax call is working and that JSON content is being returned to the browser. I'm not sure what might be wrong. I'm binding to a List collection of Batch objects. A Batch object has properties to be displayed in the first level of the grid. The Batch object also has a property that returns a List collection of Transaction objects which will be displayed on demand in the nested grid which I haven't gotten to yet.
Can anyone point me to where I've gone wrong? I've no clue what to do next and can't find any articles that look like a solution.
Here's the code I have so far:
// the controller
// called by Index2: returns a list of BatchHeader objects directly from the ROAMHostSvc
public ActionResult FetchBatchList2()
{
DateTime aDate = new DateTime(0001, 1, 1);
ROAMHostSvc.Notification messages1 = null;
ROAMHostSvc.ROAMHostSvcClient hostSvc = null;
KUI_CS_Test1.ROAMHostSvc.BatchHeader[] batchArr;
//List<
KUI_CS_Test1.ROAMHostSvc.BatchHeader
> batchCollection = new List<
BatchHeader
>();
try
{
hostSvc = new ROAMHostSvc.ROAMHostSvcClient();
batchArr = hostSvc.GetBatchCollection(ref messages1, false, aDate, aDate, false, aDate, aDate);
// assign the objects in the array to the List collection
//for (int i = 0; i <= batchArr.Length - 1; i++)
//{
// batchCollection.Add(batchArr[i]);
//}
//return View(batchCollection);
//return PartialView(batchCollection);
//return PartialView(Json(batchCollection, JsonRequestBehavior.AllowGet));
return Json(batchArr, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return null;
}
finally
{
Close_WCF_Service(ref hostSvc);
}
}
private void Close_WCF_Service(ref ROAMHostSvc.ROAMHostSvcClient hostSvc)
{
try
{
if ((hostSvc != null))
{
if (hostSvc.State == System.ServiceModel.CommunicationState.Opened)
{
hostSvc.Close();
hostSvc = null;
}
}
}
catch (Exception ex)
{
throw;
}
}
}
//the view
@model KUI_CS_Test1.ROAMHostSvc.BatchHeader[]
@{
ViewBag.Title = "Index1";
}
<
h2
>Index1</
h2
>
@(Html.Kendo().Grid(Model)
.Name("batchGrid")
.Columns(columns =>
{
columns.Bound(b => b.BatchID);
columns.Bound(b => b.Transmitted_DateTime);
columns.Bound(b => b.Completed_DateTime);
columns.Bound(b => b.Created_DTTM);
columns.Bound(b => b.Created_EmpID);
}
)
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("FetchBatchList2", "Home"))
)
)
13 Answers, 1 is accepted
Welcome to the Kendo UI family. Please take a look at this Grid demo and notice the structure of the Action method which is used as a Read Action for the dataSource. As a minimum It should have a parameter of type [DataSourceRequest] DataSourceRequest which contains the information about the current state of the grid and should return the result using the ToDataSourceResult extension method. I would also suggest you to check this page about Grid Troubleshooting.
Please let me know if this information solved the problem.
Dimiter Madjarov
the Telerik team
I could use a steer on how to make the next level work and a demo on formatting data. I looked at the hierarchy demo at http://demos.kendoui.com/web/grid/hierarchy.html but it's not germane to my case as I'm not querying a database table.
In my master level grid I get a List of BatchHeader objects. I want to create a detail level using a collection property of BatchHeader, e.g. a List of Transaction objects. How to I reference the BatchHeader object of a row that get's clicked in order to access the List collection of Transactions as the data source for my detail grid? Since I already got those from the service I don't want to have to query the service again.
Thanks!
BTW, it would be most helpful if there were a book on the Kendo UI. The documentation as it currently exists is really difficult to use for someone new to Kendo. I'm spending a lot of time searching and not finding what I need.
Since you already received the data for the detail grid, you could set it's dataSource explicitly in the DetailInit event of the master grid.
E.g.
@(Html.Kendo().Grid<Customer>()
.Name(
"Grid"
)
.Columns(columns => {
columns.Bound(p => p.Name);
columns.Bound(p => p.Years);
})
.ClientDetailTemplateId(
"products"
)
.Events(e => e.DetailInit(
"detailInit"
))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action(
"Customers_Read"
,
"Home"
))
)
)
<script id=
"products"
type=
"text/kendo-tmpl"
>
@(Html.Kendo().Grid<Product>()
.Name(
"Products_#=Name#"
)
.ToClientTemplate()
)
</script>
<script>
function
detailInit(e) {
var
grid = $(
"#Products_"
+ e.data.Name).data(
"kendoGrid"
);
grid.dataSource.data(e.data.Products);
}
</script>
Let me know if this covers your scenario.
Greetings,
Dimiter Madjarov
the Telerik team
I'll work through this, probably on Monday... I'm off till then. thanks for the info and I'll post my results soon.
[code]
@model IEnumerable<KUI_CS_Test1.ROAMHostSvc.BatchHeader>
[/code]
I tried
[code]
<script id="transactions" type="text/kendo-tmpl">
@(Html.Kendo().Grid(KUI_CS_Test1.ROAMHostSvc.BatchHeader.TranCollection)
.Name("Transactions_#=BatchID#")
.ToClientTemplate()
)
</script>
[/code]
but the page can't find a reference to that property. I noticed you used angle brackets vs parentheses. Does it make any difference? I used parentheses in the master grid declaration and it works. I was wondering it it's because the detail grid is declared in a script block that it might change. I don't seem to get an error either way.
Thanks!
Rich
The model cannot be passed directly in parenthesis for the detail grid, because the grid won't know which row from the master grid are we referring to and which TranCollection to bind to. For the current scenario you should use the angle brackets syntax and set the dataSource in the detailInit event, as shown in the previous example. In the event handler you could refer to the property as e.data.TranCollection.
Dimiter Madjarov
the Telerik team
I think I'm close but still can't quite figure out the syntax to tell the detail grid it's to receive an enumerable List of type ITransaction, e.g. the BatchHeaders TranCollection property, which at runtime can hold transactions of various types. One way I tried it gave me an error that I was using a property as a type. Here's my current code... can you tell me where I'm going wrong? None of the examples I've seen are quite like what I'm trying to do. The master level works, but the detail level can't resolve the column properties. I've tried it a bunch of different ways that don't work. Perhaps I'm reading the examples wrong?
Thanks!
@model IEnumerable<
KUI_CS_Test1.ROAMHostSvc.BatchHeader
>
@{
ViewBag.Title = "Kendo UI for MVC (C#) Test App";
}
<
h2
>Batch List</
h2
>
@(Html.Kendo().Grid(Model)
.Name("batchGrid")
.Sortable()
.Pageable()
.Filterable()
.Columns(columns =>
{
columns.Bound(b => b.BatchID)
.Width("22%");
columns.Bound(b => b.Transmitted_DateTime)
.Width("13%")
.Format("{0:MM/dd/yyyy hh:mm tt}")
.Title("Transmitted");
columns.Bound(b => b.Completed_DateTime)
.Width("13%")
.Format("{0:MM/dd/yyyy hh:mm tt}")
.Title("Completed");
columns.Bound(b => b.Created_DTTM)
.Width("13%")
.Format("{0:MM/dd/yyyy hh:mm tt}")
.Title("Created");
columns.Bound(b => b.Created_Emp_Name)
.Width("18%")
.Title("Created By");
}
)
.ClientDetailTemplateId("transactions")
.Events(e => e.DetailInit("detailInit"))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("FetchBatchList2", "Home"))
)
)
<
script
id
=
"transactions"
type
=
"text/kendo-tmpl"
>
@(Html.Kendo().Grid<
IEnumerable
<KUI_CS_Test1.ROAMHostSvc.BatchHeader.ITransaction>>()
.Name("Transactions_#=BatchID#")
.Columns( columns =>
{
columns.Bound(t => t.ID).Width("22%");
columns.Bound(t => t.Version);
columns.Bound(t => t.TranTypeDisplayText);
columns.Bound(t => t.PostingFlagDisplayText);
columns.Bound(t => t.Posting_DTTM);
columns.Bound(t => t.PostingMessage);
})
.ToClientTemplate()
)
</
script
>
<
script
type
=
"text/javascript"
language
=
"javascript"
>
function detailInit(e) {
var grid = $("#Transactions_" + e.data.TranCollection).data("kendoGrid");
grid.dataSource.data(e.data.Transactions);
}
</
script
>
As far as I can see, the child Grid is not correctly referred in the jQuery selector in the detailInit event. Assuming that the name of the Grid is "Transactions_#=BatchID#", it should be selected the following way:
var
grid = $(
"#Transactions_"
+ e.data.BatchID).data(
"kendoGrid"
);
Dimiter Madjarov
the Telerik team
I think I'm making progress, but I'm not sure... sorry to be such a pest... I'm new to both C#, MVC, and Kendo and I never seem to be doing the easy stuff first!
Now I'm getting an error when the page parses so I'm not sure I've resolved the detail grid object reference correctly. The error I'm getting is 'Cannot convert lambda expression to typoe 'string' because it is not a delagate type.'
Type TransactionBase is the ancestor of the current transaction type I'm using which is controlled by interface ITransaction. All of the properties and methods needed are available in TransactionBase. In the current case BatchHeader contains a List of InventoryTransaction objects derived from TransactionBase. The interface isn't showing up in the WCF service that provides the List but that's a different problem... I think this should work, although I'd prefer to specify ITransaction. I can solve for that later though.
Now I'm getting past base the object reference but the column binding is complaining. For some reason I'm no longer getting Intellisense on the code block so I can't tell the that the object reference doesn't resolve until I run the page.
Here's the code I have now for the detail grid and event...
<
script
id
=
"transactions"
type
=
"text/kendo-tmpl"
>
@(Html.Kendo().Grid<
IEnumerable
<KUI_CS_Test1.ROAMHostSvc.TransactionBase>>()
.Name("Transactions_#=BatchID#")
.Columns( columns =>
{
columns.Bound(t => t.ID).Width("22%");
columns.Bound(t => t.Version);
columns.Bound(t => t.TranTypeDisplayText);
columns.Bound(t => t.PostingFlagDisplayText);
columns.Bound(t => t.Posting_DTTM);
columns.Bound(t => t.PostingMessage);
})
.ToClientTemplate()
)
</
script
>
<
script
type
=
"text/javascript"
language
=
"javascript"
>
function detailInit(e) {
var grid = $("#Transactions_" + e.data.BatchID).data("kendoGrid");
grid.dataSource.data(e.data.TranCollection);
}
</
script
>
When initializing the Grid, you should use the angle brackets to specify the type of the Grid items. I am assuming that in the current scenario it should be
@(Html.Kendo().Grid<
KUI_CS_Test1.ROAMHostSvc.TransactionBase
>()
@(Html.Kendo().Grid<
IEnumerable
<KUI_CS_Test1.ROAMHostSvc.TransactionBase>>()
If this does not solve the issue, could you send me a sample project, so I could investigate it locally and assist you further.
Regards,
Dimiter Madjarov
the Telerik team
One last question... the grid is rendering fine now, but the selector column of the master grid is very wide. I searched for ways to configure it but didn't find any way to reference that column which seems to be automatically added. The demos don't show any formatting of this.
Will this adjust to the aggregate width of all the other columns?
Thank you very much for your help and your patience!
Here's the format spec:
columns.Bound(t => t.Posting_DTTM)
.Width("15")
.Format("{0:MM/dd/yyyy hh:mm tt}")
.Title("Posting Date/Time");
/Date(1361913899000)/
The entire object List was sent to the browser by the following code:
public ActionResult FetchBatchList2([Kendo.Mvc.UI.DataSourceRequest]DataSourceRequest request)
{
DateTime aDate = new DateTime(0001, 1, 1);
ROAMHostSvc.Notification messages1 = null;
ROAMHostSvc.ROAMHostSvcClient hostSvc = null;
KUI_CS_Test1.ROAMHostSvc.BatchHeader[] batchArr;
try
{
// call the WCF service for the List of BatchHeader objects
hostSvc = new ROAMHostSvc.ROAMHostSvcClient();
batchArr = hostSvc.GetBatchCollection(ref messages1, false, aDate, aDate, false, aDate, aDate);
// assign the result to the DataSourceResult object and return that as Json
var result = new DataSourceResult()
{
Data = batchArr,
Total = batchArr.Length
};
return Json(result);
}
catch (Exception ex)
{
return null;
}
finally
{
Close_WCF_Service(ref hostSvc);
}
}
Thanks!
The dataSource will parse the dates only when they are loaded through its transport. When using the data method, you should parse the dates with custom code before using the method e.g.
function
detailInit(e) {
var
grid = $(
"#Transactions_"
+ e.data.BatchID).data(
"kendoGrid"
);
var
detailData = e.data.TranCollection;
for
(
var
i = 0; i < detailData.length; i++) {
detailData[i].Posting_DTTM = kendo.parseDate(detailData[i].Posting_DTTM);
}
grid.dataSource.data(detailData);
}
Daniel
the Telerik team