This is a migrated thread and some comments may be shown as answers.

Set datasouce of child grid using datasource of parent grid in Kendo UI

3 Answers 96 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Ashish
Top achievements
Rank 1
Veteran
Ashish asked on 23 Dec 2020, 04:16 PM

I have this form:

@*Some form fields here that accept startDate and endDate*@
 
<div>
    <button id="searchButton">Search</button>
</div>
<div class="col-md-12 row">
    @(Html.Kendo()
            .Grid<ProjectName.DataModels.Models.Customer>()
            .Name("CustomerGrid")
            .Columns(columns =>
            {
                columns.Bound(e => e.CustomerId);
                columns.Bound(e => e.SomeCustomerColumn);
            })
            .ClientDetailTemplateId("OrderDetails")
            .AutoBind(false) // Don't load the data yet because I'll need to supply parameters for the fetch
            .DataSource(dataSource => dataSource
                        .Ajax()
                        .Events(events=>events.Change("loadChildGrid"))
                        .PageSize(20)
                        .Model(model => model.Id("CustomerId", typeof(string)))
                        .Read(read => read.Action("GetCustomersAsync", "Customer").Data("passArguments"))
            )
    )
 
    <script id="OrderDetails" type="text/kendo-tmpl">
        @(Html.Kendo()
                .Grid<ProjectName.DataModels.Models.Order>()
                .Name("OrderDetails_#=CustomerId#")
                .Columns(columns =>
                {
                    columns.Bound(o => o.ProductName);
                    columns.Bound(o => o.SomeOrderColumn);
                })
                .DataSource(dataSource => dataSource
                            .Ajax()
                            .PageSize(10)
                            .Model(model=>model.Id("OrderId"))
                            .ServerOperation(false)
                )
                .AutoBind(false)
                .ToClientTemplate()
        )
    </script>
</div>
  
<script type="text/javascript">
    $("#searchButton").on("click", function () {
        // Load the customerGrid here:
        $("#CustomerGrid").data("kendoGrid").dataSource.read();
    });
     
    function passArguments() {
        var startDate = $("#startdate").data("kendoDatePicker").value();
        var endDate = $("#enddate").data("kendoDatePicker").value();
        return {
            start: startDate,
            end: endDate
        }
    }
     
    // QUESTION: How to load the child grid: OrderDetails_123 by using datasource from the parent grid?
    // THIS IS WHAT I'VE TRIED SO FAR:
    function loadChildGrid() {
        var parentData = $("#CustomerGrid").data("kendoGrid").dataSource.data();
        //Initialize the  child grid
        $.each(parentData, childDataFeeder);
    }
     
    function childDataFeeder(index, item) {
        var childGridName = "#" + "OrderDetails_" + item.CustomerId;
        var childGrid = childGridName.data("kendoGrid");
        childGrid.dataSource.data(value.Orders)
    }
</script>

And a method in the Customer controller:

public async Task<ActionResult> GetCustomersAsync([DataSourceRequest] DataSourceRequest request, DateTime start, DateTime end)
{
    var customersWithOrders = GetDataForParentAndChildGrid(start, end);
    return Json(consolidatedData.ToDataSourceResult(request));
}
 
private List<Customer> GetDataForParentAndChildGrid(DateTime start, DateTime end)
{
    var testData = new List<Customer>();
    // Gets required data with those dates filter and perform some mathematical calculations
    testData.Add(new Customer
    {
        CustomerId = "123",
        SomeCustomerColumn = "Blah blah",
        Orders = new List<Order>()
        {
            new Order{
                OrderId = "123ABC",
                CustomerId = "123",
                SomeOrderColumn = "Blah Blah Blah"
            }
        }
    });
    return testData;
}

My goal is to set the 'dataSource' of child grid using data that is already available from the main grid. What I've tried so far is that I have attached 'Change' event to the main grid which fires 'loadChildGrid' function where I try to extract the data from main grid and pass every item of it to a 'childDataFeeder' function to initialize the 'dataSource' of child grid. The issue here is that when it tries to do that, the child grid doesn't exist yet (because it's not created by Kendo until a user clicks on the expand icon in the main grid).
You can see what I've tried so far in the 'childDataFeeder' method(without any success). So I'd greatly appreciate your direction on this.
Thank You!

3 Answers, 1 is accepted

Sort by
0
Ashish
Top achievements
Rank 1
Veteran
answered on 23 Dec 2020, 04:18 PM

This question has recent updates than the original one, so that original can be deleted:

https://www.telerik.com/forums/set-datasouce-of-a-child-grid-from-the-datasource-of-parent-grid-in-kendo-ui-for-net-core

0
Ashish
Top achievements
Rank 1
Veteran
answered on 23 Dec 2020, 06:22 PM

After so many hours of hit and trial, I finally solved it. So I'm posting it here to save someone else's time if they come across a similar problem:
I added a `DetailExpand` event to the main grid. And removed the `Change` event on the `dataSource`.

@(Html.Kendo()
        .Grid<ProjectName.DataModels.Models.Customer>()
        .Name("CustomerGrid")
        .Columns(columns =>
        {
            columns.Bound(e => e.CustomerId);
            columns.Bound(e => e.SomeCustomerColumn);
        })
        .ClientDetailTemplateId("OrderDetails")
        .AutoBind(false) // Don't load the data yet because I'll need to supply parameters for the fetch
        .DataSource(dataSource => dataSource
                    .Ajax()
                    .PageSize(20)
                    .Model(model => model.Id("CustomerId", typeof(string)))
                    .Read(read => read.Action("GetCustomersAsync", "Customer").Data("passArguments"))
        )
        .Events(events => events.DataBound("dataBound").DetailExpand("onExpand"))
)

 

Now the callback function called `onExpand` will be called every time we expand a row in the parent grid. This is where I will now set the child grid's `dataSource`.

// Passing e is also important here because if you don't, this callback gets called
// for every row in the main grid (even when you don't expand them!)
function onExpand(e) {
    var customerId = e.sender.dataItem(e.masterRow).CustomerId;
    var orders = e.sender.dataItem(e.masterRow).Orders;
    //Initialize the  child grid as well
    var childGridName = "#" + "OrderDetails_" + customerId;
 
    var childGrid = $(childGridName).data("kendoGrid");
    if (childGrid !== undefined) {
        childGrid.dataSource.data(orders);
    }
}
 
function dataBound() {
    this.expandRow(this.tbody.find("tr.k-master-row").first());
}

 

I used `e.sender.dataItem(e.masterRow).PROPERTYNAME` to access the properties that I need from the master row.

This works flawlessly now!

I posted this answer in Stackoverflow as well.

0
Nikolay
Telerik team
answered on 28 Dec 2020, 07:53 AM

Hello Ashish,

I am happy to hear you have managed to resolve this and thank you for posting the solution you came up with here and in the SO thread. This, I believe, will help others facing the same scenario.

Indeed, the DetailExpand event will fire when the user expands a detail table row and it can be used to pass the data from the master to the child grid.

Kind regards,
Nikolay
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Tags
Grid
Asked by
Ashish
Top achievements
Rank 1
Veteran
Answers by
Ashish
Top achievements
Rank 1
Veteran
Nikolay
Telerik team
Share this question
or