Nested Kendo Grid Using Angular

In this article, we are going to learn about implementing nested Kendo Grid, using angular js and Webapi in ASP.NET MVC 5 Web Application. In previous articles we learned about implementing CRUD operations in Kendo Grid using Angular js framework with WebAPI. If you are new to Web API, please refer previous posts.

Note: If you are not comfortable with Angular js, you can also implement Kendo Grid, using jQuery. Also please refer to   Implementing CRUD operations on kendo grid using jquery. Angular Kendo Grid also internally uses jQuery for the data operations (retrieval, update, delete etc).

Now, let's discuss about our new tutorial Nested Kendo Grid implementation in this article.

Create a Basic Kendo grid using angular js

  1. Please refer to this previous post link to implement the basic Kendo Grid (Here, I am extending the previous sample Application).
  2. This is the screen shot of final nested Kendo Grid.

    grid

  3. I will explain the changes, I did, step by step.

Add another table to DB

  1. Here, I created another table "TDetails" to show the nested details for a grid row.
  2. Schema definition for TDetails are as follows-
    1. CREATE TABLE [dbo].[TDetails] (  
    2. [DetailsID] INT IDENTITY (1, 1) NOT NULL,  
    3. [CompanyName] VARCHAR (50) NOT NULL,  
    4. [Salary] VARCHAR (50) NOT NULL,  
    5. [Location] VARCHAR (50) NOT NULL,  
    6. [StudentID] INT NULL,  
    7. PRIMARY KEY CLUSTERED ([DetailsID] ASC)  
    8. );  
  3. Now, click StudentEntity.edmx file in Models folder. You will get an Entity diagram, as shown below-

    Models

  4. Click Update Model from the database and add the table, you recently created to StudentEntity.edmx.
  5. Here, I already added the Table.

    Table

Add a new method to api Controller

  1. Add the code, given below, to get JSON data for the nested grid.
    1. [HttpGet]  
    2.         [Route("StudentDetails/{id}")]  
    3.         public HttpResponseMessage GetStudentDetails(int id)  
    4.         {  
    5.             try  
    6.             {  
    7.                 var studesription = db.TDetails.Where(a => a.StudentID.Equals(id)).ToList();  
    8.                 return Request.CreateResponse(HttpStatusCode.OK, studesription, Configuration.Formatters.JsonFormatter);  
    9.   
    10.             }  
    11.             catch (Exception ex)  
    12.             {  
    13.                 return Request.CreateResponse(HttpStatusCode.OK, ex.Message, Configuration.Formatters.JsonFormatter);  
    14.             }  
    15.         }  
  2. This method gets the data from API controller, based on StudentID. Add the extra code, given below, to view-

  3. Add the extra code, given below, to Index view to make Kendo nested-
    1. <!--Kendo ui elements-->  
    2.     <div id="example" ng-app="KendoGridDemo">  
    3.         <h3>CRUD operations on Kendo grid using Angualr JS & webapi</h3>  
    4.         <div ng-controller="Controller">  
    5.             <kendo-grid k-options="mainGridOptions">  
    6.                 <!--nested grid template start-->  
    7.                 <div k-detail-template>  
    8.                     <div>  
    9.                         <div kendo-grid k-options="subgridOptions(dataItem)">  
    10.                         </div>  
    11.                     </div>  
    12.                 </div>  
    13.                 <!--nested grid template end-->  
    14.             </kendo-grid>  
    15.         </div>  
    16.     </div>  
  4. I added the nested grid template to the main grid. 5. Add the scripting code, given below, to populate the nested grid with the data.
    1. //add this code in maingrid options  
    2. dataBound: function () {  
    3.                         this.expandRow(this.tbody.find("tr.k-master-row").first());  
    4.                     },  
    5.   
    6. //nested grid oprtions  
    7. $scope.subgridOptions = function (dataItem) {  
    8.                     return {  
    9.                         dataSource: {  
    10.                             type: "json",  
    11.                             transport: {  
    12.                                 read: {  
    13.                                     url: "http://localhost:13547/api/TStudentsAPI/StudentDetails/" + dataItem.StudentID,  
    14.                                     dataType:"json"  
    15.                                 }  
    16.                             },  
    17.                             serverPaging: true,  
    18.                             serverSorting: true,  
    19.                             serverFiltering: true,  
    20.                             pageSize: 5,  
    21.                         },  
    22.                         scrollable: false,  
    23.                         sortable: true,  
    24.                         pageable: true,  
    25.                         columns: [  
    26.                         {  
    27.                             field: "DetailsID",  
    28.                             title: "DetailsID",  
    29.                             width: "180px"  
    30.                         },  
    31.                         {  
    32.                             field: "CompanyName",  
    33.                             title: "Company Name",  
    34.                             width: "180px"  
    35.                         },  
    36.                         {  
    37.                             field: "Salary",  
    38.                             title: "Salary",  
    39.                             width: "180px"  
    40.                         },  
    41.                         {  
    42.                             field: "Location",  
    43.                             title: "Location",  
    44.                             width: "180px"  
    45.                         },  
    46.                           
    47.                         ]  
    48.                     };  
  5. The complete Index view code after the changes are given below- 
    1. <!--Kendo style reference files-->  
    2. <link rel="stylesheet" href="//kendo.cdn.telerik.com/2016.2.714/styles/kendo.common.min.css" />  
    3. <link rel="stylesheet" href="//kendo.cdn.telerik.com/2016.2.714/styles/kendo.flat.min.css" />  
    4. <link rel="stylesheet" href="//kendo.cdn.telerik.com/2016.2.714/styles/kendo.default.mobile.min.css" />  
    5.   
    6. <!--kendo script reference files-->  
    7. <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>  
    8. <script src="http://kendo.cdn.telerik.com/2016.1.412/js/angular.min.js"></script>  
    9. <script src="http://kendo.cdn.telerik.com/2016.1.412/js/jszip.min.js"></script>  
    10. <script src="http://kendo.cdn.telerik.com/2016.1.412/js/kendo.all.min.js"></script>  
    11.   
    12. <!--Kendo ui elements-->  
    13. <div id="example" ng-app="KendoGridDemo">  
    14.     <h3>CRUD operations on Kendo grid using Angualr JS & webapi</h3>  
    15.     <div ng-controller="Controller">  
    16.         <kendo-grid k-options="mainGridOptions">  
    17.             <!--nested grid template start-->  
    18.             <div k-detail-template>  
    19.                 <div>  
    20.                     <div kendo-grid k-options="subgridOptions(dataItem)">  
    21.                     </div>  
    22.                 </div>  
    23.             </div>  
    24.             <!--nested grid template end-->  
    25.         </kendo-grid>  
    26.     </div>  
    27. </div>  
    28.   
    29. <script>  
    30.     //Create a anular app and controller add kendo dependency to app  
    31.     angular.module("KendoGridDemo", ["kendo.directives"])  
    32.         .controller("Controller"function ($scope) {  
    33.             //specify kendo grid options  
    34.             $scope.mainGridOptions = {  
    35.                 dataSource: {  
    36.                     type: "json",   //data type  
    37.                     transport: {                            
    38.                         destroy: {  
    39.                             url: "api/TStudentsAPI",  
    40.                             type: "DELETE"  
    41.                         }, read: {  
    42.                             url: "http://localhost:13547/api/TStudentsAPI",  
    43.                             dataType: "json",  
    44.                         },  
    45.                         create:  
    46.                         {  
    47.                             url: "http://localhost:13547/api/TStudentsAPI",  
    48.                             type: "POST"  
    49.                         },  
    50.                         update:  
    51.                         {  
    52.                             url: "api/TStudentsAPI",  
    53.                             type: "PUT",                                 
    54.                             parameterMap: function (options, operation) {  
    55.                                 if (operation !== "read" && options.models) {  
    56.                                     return {  
    57.                                         models: kendo.stringify(options.models)  
    58.                                     };  
    59.                                 }  
    60.                             }  
    61.                         },  
    62.                     },  
    63.                     schema: //schema of the table data  
    64.                              {  
    65.                                  model:  
    66.                                  {  
    67.                                      id: "StudentID",  
    68.                                      fields: {  
    69.                                          StudentID: { editable: false, nullable: false, type: "number" },  
    70.                                          FullName: { editable: true, nullable: true, type: "string" },  
    71.                                          Contact: { editable: true, nullable: true, type: "number" },  
    72.                                          Country: { editable: true, nullable: true, type: "string" },  
    73.                                          Designation: { editable: true, nullable: true, type: "string" }  
    74.                                      }  
    75.                                  }  
    76.                              },  
    77.                     pageSize: 5,  
    78.                     serverPaging: true,  
    79.                     serverSorting: true  
    80.                 },  
    81.                 editable: "popup",      //editable type popup/inline/batch  
    82.                 toolbar: ["create"],    //toolbar options  
    83.                 sortable: {  
    84.                     mode: "single",  //sorting  
    85.                     allowUnsort:true  
    86.                 },          
    87.                 pageable: {          //paging  
    88.                     buttonCount: 5  
    89.                 },          
    90.                 resizeable: true,       //resizing  
    91.                 scrollable: false,  
    92.                 dataBound: function () {  
    93.                     this.expandRow(this.tbody.find("tr.k-master-row").first());  
    94.                 },  
    95.                 //specify columns that you want to display   
    96.                 columns: [{  
    97.                     field: "StudentID",  
    98.                     title: "Student ID",  
    99.                     width: "180px"  
    100.                 },  
    101.                 {  
    102.                     field: "FullName",  
    103.                     title: "FullName",  
    104.                     width: "180px"  
    105.                 },  
    106.                 {  
    107.                     field: "Contact",  
    108.                     title: "Contact",  
    109.                     width: "180px"  
    110.                 },  
    111.                 {  
    112.                     field: "Country",  
    113.                     title: "Country",  
    114.                     width: "180px"  
    115.                 },  
    116.                 {  
    117.                     field: "Designation",  
    118.                     title: "Designation",  
    119.                     width: "180px"  
    120.                 },  
    121.                 //actions columns contains-- edit/delete   
    122.                     {  
    123.                         title:"Actions",  
    124.                         command: ["edit",  
    125.                         {  
    126.                             name: "destroy",  
    127.                             text: "Delete",  
    128.                             width: "120px"  
    129.                         }  
    130.                         ],  
    131.                     }  
    132.                 ]  
    133.             };  
    134.             $scope.subgridOptions = function (dataItem) {  
    135.                 return {  
    136.                     dataSource: {  
    137.                         type: "json",  
    138.                         transport: {  
    139.                             read: {  
    140.                                 url: "http://localhost:13547/api/TStudentsAPI/StudentDetails/" + dataItem.StudentID,  
    141.                                 dataType:"json"  
    142.                             }  
    143.                         },  
    144.                         serverPaging: true,  
    145.                         serverSorting: true,  
    146.                         serverFiltering: true,  
    147.                         pageSize: 5,  
    148.                     },  
    149.                     scrollable: false,  
    150.                     sortable: true,  
    151.                     pageable: true,  
    152.                     columns: [  
    153.                     {  
    154.                         field: "DetailsID",  
    155.                         title: "DetailsID",  
    156.                         width: "180px"  
    157.                     },  
    158.                     {  
    159.                         field: "CompanyName",  
    160.                         title: "Company Name",  
    161.                         width: "180px"  
    162.                     },  
    163.                     {  
    164.                         field: "Salary",  
    165.                         title: "Salary",  
    166.                         width: "180px"  
    167.                     },  
    168.                     {  
    169.                         field: "Location",  
    170.                         title: "Location",  
    171.                         width: "180px"  
    172.                     },  
    173.                       
    174.                     ]  
    175.                 };  
    176.             };  
    177.         });  
    178. </script>  
  6. Now, run the Application and see the output in the Browser. 
  7. Download the source code for this Application here Source Code(VS2015 code) .

Conclusion

I hope, this tutorial is understandable and useful for every reader. Please comment, if you have suggestions for any modification to improve the quality of an article. Please see this article in my blog Nested Kendo Grid.