ASP Core, custom Client Detail Template of Grid component

1 Answer 407 Views
Grid
Stefan
Top achievements
Rank 1
Stefan asked on 07 Dec 2021, 02:50 AM

I'm new to ASP Core Grid component. I need to build a custom detail template. It has a child grid with its own data source. But it also have some info above the child grid. I started with the 'Grid and Menu' Visual Studio project template and removed unnecessary code. I've attached the UI screenshot and copied the content of Index.cshtml below. I have the following questions:

  1. The Freight in the detail template is decimal type. How to format it to '0.##'?
  2. I want to show some information in the detail template that could be part of the master record but cannot be loaded as part of the master record, it's a big performance hit if done that way. So it must be loaded later when the detail expands. I thought I can use the DetailInit event on the master grid but how do I update the UI? Do I re-render the template, do I update the master data record and then refresh the UI somehow?
  3. I have Refresh button on the detail grid pager. Can I update the entire template (including the Freight and summary info above the detail grid) when this button is clicked? Are there any events I can use to perform (2.) above? Is there a better way?

Any pointers are greatly appreciated.

Thank you!

Index.cshtml:

@{
    ViewData["Title"] = "Home Page";
}

<div class="row">
    <div class="col-12">
        @(Html.Kendo().Grid <GridDetail.Models.OrderViewModel>()
            .Name("grid")
            .Columns(columns =>
            {
                columns.Bound(p => p.OrderID).Filterable(false);
                columns.Bound(p => p.OrderDate).Format("{0:MM/dd/yyyy}");
                columns.Bound(p => p.ShipName);
                columns.Bound(p => p.ShipCity);
            })
            .HtmlAttributes(new { style = "height:550px;" })
            .ClientDetailTemplateId("detailTemplate")
            .DataSource(dataSource => dataSource
                .Ajax()
                .PageSize(20)
                .Read(read => read.Action("Orders_Read", "Grid"))
                )
        )
    </div>
</div>

<script id="detailTemplate" type="text/html">
    <div>Freight: #=Freight#.</div> <!-- How to format the Freight? -->
    <div>
        Here some information that could come from shared data source.
        Or it could be on the master grid record but loaded when the detail expands.
    </div>
    @(Html.Kendo()
        .Grid<GridDetail.Models.OrderDetailViewModel>()
        .Name("grid_#=OrderID#")
        .Columns(columns =>
        {
            columns.Bound(c => c.Item);
            columns.Bound(c => c.Quantity);
        })
        .DataSource(dataSource => dataSource
            .Ajax()
            .PageSize(10)
            .Read(read => read.Action("Order_Details_Read", "Grid", new { orderId = "#=OrderID#" }))
        )
        // Can the pager refresh be used to trigger update to the entire detailTemplate?
        // Is there even that could be used?
        .Pageable(pager => pager.Refresh(true))
        .ToClientTemplate()
    )
</script>

 

1 Answer, 1 is accepted

Sort by
0
Accepted
Stoyan
Telerik team
answered on 09 Dec 2021, 05:37 PM

Hi Stefan,

Thank you for sharing your code. It is helpful to understand the scenario at hand.

  1. To format the Freight property use the kendo.toString method
    <div>Freight: #=kendo.toString(Freight, "#.##")#.</div> 
  2. To add a custom content to the template, which comes separately from the server, I would recommend you to add a class to the targeted div element.
    <div class="additional-content">
            Here some information that could come from shared data source.
            Or it could be on the master grid record but loaded when the detail expands.
    </div>
    Then when the document has loaded you can send a request to the server and populate the div with the response.
    $(document).ready(function(){
              requestServerData(parentId);
    })
    function requestServerData(id) {
            $.ajax({
                url: "Home/ServerData",
                data: { Id: parentId },  
                success: function (response) {
                    $(".additional-content").text(response);
                }
            })
     }
  3. The Refresh button of the Grid's Pager sends a new read request to the server. You can handle the mousedown event of the button and in the handler get the DataItem of the Parent row.
     $(".k-pager-refresh").on("mousedown", function(e){
                //GET THE DETAIL GRID WRAPPER
                var detailGridWrapper = $(e.target).parent().parent().parent())
                 // GET PARENT ROW ELEMENT
                 var parentRow = detailGridWrapper.closest("tr.k-detail-row").prev("tr");
                // GET PARENT GRID ELEMENT
                var parentGrid = parentRow.closest("[data-role=grid]").data("kendoGrid");
                // GET THE PARENT ROW MODEL
                var parentModel = parentGrid.dataItem(parentRow);
                requestServerData(parentModel.OrderId)
            })
    This is useful, if you need to pass an Id to the ServerData Action Method to filter the server response.

I hope the information above helps you achieve your requirement.

Regards,
Stoyan
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Stefan
Top achievements
Rank 1
commented on 11 Dec 2021, 10:25 PM

Thank you Stoyan! This is exactly what I needed. Below is the final working solution.

Index.cshtml

@{
    ViewData["Title"] = "Home Page";
}

<div class="row">
    <div class="col-12">
        @(Html.Kendo().Grid <GridDetail.Models.OrderViewModel>()
            .Name("grid")
            .Columns(columns =>
            {
                columns.Bound(p => p.OrderId).Filterable(false);
                columns.Bound(p => p.OrderDate).Format("{0:MM/dd/yyyy}");
                columns.Bound(p => p.ShipName);
                columns.Bound(p => p.ShipCity);
            })
            .HtmlAttributes(new { style = "height:550px;" })
            .ClientDetailTemplateId("detailTemplate")
            .DataSource(dataSource => dataSource
                .WebApi()
                .PageSize(10)
                .Read(read => read.Action("Orders_Read", "Grid"))
                .Model(m => { m.Id(c => c.OrderId); })
                )
            .Pageable().Scrollable()
            .Events(e => e.DetailInit("detailInit"))
        )
    </div>
</div>

<script id="summaryTemplate" type="text/html">
    #: CustomerName#.
</script>

<script id="detailTemplate" type="text/html">
    <div>
        Freight: #=kendo.toString(Freight, "\\#.\\#\\#")#. Date: #=kendo.toString(OrderDate, "MM/dd/yyyy")#.
        <span id="summary_#=OrderId#"></span>
    </div>

    @(Html.Kendo()
    .Grid<GridDetail.Models.OrderDetailViewModel>()
    .Name("grid_#=OrderId#")
    .Columns(columns =>
    {
        columns.Bound(c => c.Item);
        columns.Bound(c => c.Quantity);
    })
    .DataSource(dataSource => dataSource
        .WebApi()
        .PageSize(5)
        .Read(read => read.Action("Order_Details_Read", "Grid", new { orderId = "#=OrderId#" }))
    )
    // Can the pager refresh be used to trigger update to the entire detailTemplate?
    // Is there even that could be used?
    .Pageable(pager => pager.Refresh(true))
    .ToClientTemplate()
)
</script>

@(Html.Kendo().DataSource<GridDetail.Models.OrderSummaryViewModel>()
    .Name("dataSourceOrderSummary")
    .Ajax(dataSource => dataSource
        .Read(read => read.Action("Order_Summary_Read", "Grid"))
        .Model(m => { m.Id(c => c.OrderId); })
    )
)

 

----------------------------------------------------

site.js

async function detailInit(e) {
    var id = e.data.OrderId;
    await refreshSummary(id);

    $(".k-pager-refresh").on("mousedown", async function(e) { await callRefreshSummary(e); });
}

async function callRefreshSummary(e) {
    var detailGridWrapper = $(e.target).parent().parent().parent();
    var parentRow = detailGridWrapper.closest("tr.k-detail-row").prev("tr");
    var parentGrid = parentRow.closest("[data-role=grid]").data("kendoGrid");
    var parentModel = parentGrid.dataItem(parentRow);

    refreshSummary(parentModel.OrderId);
}

async function refreshSummary(id) {
    dataSourceOrderSummary.transport.options.read.data = { orderId: id };
    _ = await dataSourceOrderSummary.read();
    rowDetail = dataSourceOrderSummary.get(id);

    var template = kendo.template($("#summaryTemplate").html());
    $("#summary_" + id).html(template(rowDetail));
}

 

Tags
Grid
Asked by
Stefan
Top achievements
Rank 1
Answers by
Stoyan
Telerik team
Share this question
or