title: Kendo UI Grid multi level hierarchy (n-levels of hierarchy)
body: <p>I am using the Kendo UI Grid and currently display parent child records appropriately.  However, it turns out that i will actually need to display n-levels vs. strictly parent-child.  Not every record will have children, but some will have multiple levels.</p>
  
  <p>Current grid code:</p>
  
  <pre><code> var jgrid = $("#boxesgrid").kendoGrid({
          columns: [
              {
                  field: "JobId",
                  hidden: true
              },
              {
                  field: "PercentComplete",
                  hidden: true
              },
              {
                  field: "JobStatusId",
                  hidden: true
              },
              {
                  field: "AppName",
                  title: "App",
                  template: "&lt;span&gt;${AppName}&lt;/span&gt;&lt;img class='health-img-r' id=app-${JobId} title='health' src='' alt='health_png' /&gt;",
                  width: "5%",
                  editable: false,
                  sortable: false
              },
              {
                  field: "JobName",
                  title: "Box Name",
                  width: "17%",
                  filterable: false
              },
              {
                  field: "StartTime",
                  title: "Start Time",
                  width: "14%",
                  filterable: false
              },
              {
                  field: "EndTime",
                  title: "End Time",
                  width: "14%",
                  filterable: false
              },
              {
                  field: "JobStatusId",
                  title: "Status",
                  template: "&lt;img class='health-img-l' id=app-${JobId} title='health' src='' alt='health_png' /&gt;&lt;span&gt;${JobStatus}&lt;/span&gt;",
                  editable: false,
                  filterable: false
              }
          ],
          sortable: {
              mode: "single",
              allowUnsort: true
          },
          pageable: {
              pageSizes: [50],
              numeric: true,
              refresh: true,
              pageSize: 50
          },
          autoBind: false,
          scrollable: false,
          resizable: true,
          detailInit: detailInit,
          dataSource: boxesDataSource,
          dataBound: function () {
              var grid = this;
              grid.tbody.find("&gt;tr").each(function () {
                  var row = $(this).closest("tr");
                  var model = grid.dataItem(row);
                  var img = $(this).find("img");
                  if (model.JobStatusId == 4 &amp;&amp; model.PercentComplete &lt; 100) {
                      img.attr("src", function() {
                          return imgSrc + imgGreen;
                      });
                  } else if (model.JobStatusId == 4) {
                      img.attr("src", function() {
                          return imgSrc + imgAmber;
                      });
                  } else if (model.JobStatusId == 7) {
                      img.attr("src", function() {
                          return imgSrc + imgIce;
                      });
                  } else if (model.JobStatusId == 8) {
                      img.attr("src", function() {
                          return imgSrc + imgHold;
                      });
                  } else if (model.JobStatusId == 5) {
                      img.attr("src", function() {
                          return imgSrc + imgBlue;
                      });
                  } else {
                      img.attr("src", function() {
                          return imgSrc + imgRed;
                      });
                  }
              });
          }
      }).data("kendoGrid");
  </code></pre>
  
  <p>Current child grid:</p>
  
  <pre><code>function detailInit(e) {
          $("&lt;div/&gt;").appendTo(e.detailCell).kendoGrid({
              dataSource: {
                  transport: {
                      read: {
                          url: "/api/BoxJobs"
                      },
                      parameterMap: function (data) {
                          data.parentid = e.data.JobId;
                          data.appid = e.data.AppId;
                          return kendo.stringify(data);
                      }
                  },
                  schema: {
                      model: { id: "JobId" }
                  },
                  serverPaging: true,
                  serverFiltering: true,
                  serverSorting: true
              },
              scrollable: false,
              sortable: true,
              columns: [
                  {
                      field: "JobId",
                      hidden: true
                  },
                  {
                      field: "PercentComplete",
                      hidden: true
                  },
                  {
                      field: "JobStatusId",
                      hidden: true
                  },
                  {
                      field: "JobName",
                      title: "Job Name",
                      template: "&lt;span&gt;${JobName}&lt;/span&gt;&lt;img class='health-img-l' id=app-${JobId} title='health' src='' alt='health_png' /&gt;",
                      width: "23%",
                      filterable: false,
                      sortable: false
                  },
                  {
                      field: "StartTime",
                      title: "Start Time",
                      width: "10%",
                      editable: false,
                      filterable: false,
                      sortable: false
                  },
                  {
                      field: "EndTime",
                      title: "End Time",
                      width: "10%",
                      editable: false,
                      filterable: false,
                      sortable: false
                  },
                  {
                      field: "ElapsedTime",
                      title: "Elapsed&lt;/br&gt;Time",
                      width: "4%",
                      editable: false,
                      filterable: false,
                      sortable: false
                  },
                  {
                      field: "MeanRunTime",
                      title: "Mean Run&lt;/br&gt;Time",
                      width: "3.5%",
                      editable: false,
                      filterable: false,
                      sortable: false
                  },
                  {
                      field: "PredecessorJobName",
                      title: "Previous Job",
                      width: "17%",
                      filterable: false,
                      sortable: false
                  },
                  {
                      field: "JobStatusId",
                      title: "Status",
                      template: "&lt;img class='health-img-l' id=app-${JobId} title='health' src='' alt='health_png' /&gt;&lt;span&gt;${JobStatus}&lt;/span&gt;",
                      editable: false,
                      filterable: false,
                      sortable: false
                  }
              ],
              dataBound: function () {
                  var grid = this;
                  grid.tbody.find("&gt;tr").each(function () {
                      var row = $(this).closest("tr");
                      var model = grid.dataItem(row);
                      var img = $(this).find("img");
                      if (model.JobStatusId == 4 &amp;&amp; model.PercentComplete &lt; 100) {
                          img.attr("src", function() {
                              return imgSrc + imgGreen;
                          });
                      } else if (model.JobStatusId == 4) {
                          img.attr("src", function() {
                              return imgSrc + imgAmber;
                          });
                      } else if (model.JobStatusId == 7) {
                          img.attr("src", function() {
                              return imgSrc + imgIce;
                          });
                      } else if (model.JobStatusId == 8) {
                          img.attr("src", function() {
                              return imgSrc + imgHold;
                          });
                      } else if (model.JobStatusId == 5) {
                          img.attr("src", function() {
                              return imgSrc + imgBlue;
                          });
                      } else {
                          img.attr("src", function() {
                              return imgSrc + imgRed;
                          });
                      }
                  });
              }
          });
      }
  </code></pre>
  
  <p>Sample top level data:</p>
  
  <pre><code>   {"Total":638,
  "Data":[
      {"JobId":1,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL_BOX","JobType":"box","TimeZone":"Chicago (Central Standard Time)","ParentJobName":null,"ParentJobId":null,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/2014 5:00:02 PM","EndTime":"","ElapsedTime":"00:58:31","JobStatusId":4,"JobStatus":"Running","MeanRunTime":"06:57:04","PercentComplete":14.00,"TotalCount":638.0,"Children":3}
      ]
  }
  </code></pre>
  
  <p>Sample 2nd level data:</p>
  
  <pre><code>[
  {"JobId":63,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL2_BOX","JobType":"box","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL_BOX","ParentJobId":1,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/2014 5:00:06 PM","EndTime":"","ElapsedTime":"00:58:27","JobStatusId":4,"JobStatus":"Running","MeanRunTime":"06:57:00","PercentComplete":14.00,"TotalCount":0.0,"Children":3},
  {"JobId":64,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL1_BOX","JobType":"box","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL_BOX","ParentJobId":1,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/2014 5:00:06 PM","EndTime":"","ElapsedTime":"00:58:27","JobStatusId":4,"JobStatus":"Running","MeanRunTime":"01:42:17","PercentComplete":57.00,"TotalCount":0.0,"Children":2},
  {"JobId":65,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL3_BOX","JobType":"box","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL_BOX","ParentJobId":1,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/2014 5:00:06 PM","EndTime":"6/2/2014 5:07:42 PM","ElapsedTime":"00:07:36","JobStatusId":5,"JobStatus":"Success","MeanRunTime":"00:03:17","PercentComplete":100.0,"TotalCount":0.0,"Children":5}
  ]
  </code></pre>
  
  <p>Sample 3rd level data:</p>
  
  <pre><code>[
  {"JobId":265,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL2_S_CLEAN1","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL2_BOX","ParentJobId":63,"PredecessorJobName":"NRS_COL2_S_TOUCH1","PredecessorJobId":266,"StartTime":"","EndTime":"","ElapsedTime":"00:58:31","JobStatusId":7,"JobStatus":"On Ice","PercentComplete":null,"Children":0},
  {"JobId":266,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL2_S_TOUCH1","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL2_BOX","ParentJobId":63,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"","EndTime":"","ElapsedTime":"00:58:31","JobStatusId":7,"JobStatus":"On Ice","PercentComplete":null,"Children":0},
  {"JobId":267,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL2_A_ZFINSNAMA","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL2_BOX","ParentJobId":63,"PredecessorJobName":"NRS_COL2_S_CLEAN1","PredecessorJobId":265,"StartTime":"6/2/2014 5:02:02 PM","EndTime":"","ElapsedTime":"00:58:31","JobStatusId":4,"JobStatus":"Running","PercentComplete":null,"Children":0}
  ]
  </code></pre>
  
  <p>I have no problem with the traditional parent-child hierarchy, but I'm struggling with even how I go about making the detail template behave for it's children.  </p>
  
  <p>I would like the template to be appropriate for child/grandchild display - no dropdown indicator if it does not have additional children.  I assume that i can evaluate the data on databound, but I'm just not seeing how to do it.</p>