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

Creating Grid with unknown columns

6 Answers 311 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Ruairi
Top achievements
Rank 1
Ruairi asked on 11 Feb 2016, 12:18 PM

I have two entities Competencies and Roles. These are both created by the user and stored in the database.

On a specific screen the user select certain Competencies and certain Roles. These then have to be displayed in a matrix.

They will then use check boxes to link the Competencies and Roles.
Each competency will be linked to several of the roles.
This matrix is completely dynamic as I do not know how many columns there will be or the names of the columns.

I know that there will be a Competency Id column and a Competency Name column. Each row will have one or more roles.
We use kendo grids throughout the application so I want to use a kendo grid.

I have tried many different ways of doing this. I have successfully passed in a System.Data.DataTable which works but is cumbersome to create. We use NHibernate and it is easier to create a model. The most successful way that I have that uses a model is as follows:

public class BasicRowModel
  {
    public string CompetencyId { get; set; }
    public string CompetencyName { get; set; }
    public List<BasicTrainingRoleModel> Roles { get; set; }
  }

public class BasicTrainingRoleModel
  {
    public string RoleName { get; set; }
    public bool RoleVal { get; set; }
  }

My view is as follows:
@model IEnumerable<BasicRowModel>
@using Models
@using System.Linq;

@{
    ViewBag.Title = "DynamicGrid2";
}

<h2>DynamicGrid2</h2>

@section scripts
{
  <script type="text/javascript" src="@Url.Content("~/Scripts/Training.js")"></script>

}

@{
  ViewBag.Title = "Administration";
  Layout = "~/Views/Shared/_Layout.cshtml";
}


@(Html.Kendo().Grid(Model)
  .Name("RoleCompsTable")
  .Columns(columns =>
  {
    columns.Bound(r => r.CompetencyId)
      .Hidden();
    columns.Bound(r => r.CompetencyName)
      .Title("Competency");
    for (int c = 0; c < ViewBag.RoleCount; c++)
    {
      //columns.Template(@<text>@item.Roles[c].RoleVal.ToString()</text>).Title(ViewBag.Roles[c]);
      columns.Bound(r => r.Roles[c].RoleVal).Title(ViewBag.Roles[c]);
    }
    //columns.Bound(r => r.Roles[0].RoleVal).Title(ViewBag.Roles[0]);
    //columns.Bound(r => r.Roles[1].RoleVal).Title(ViewBag.Roles[1]);
    //columns.Bound(r => r.Roles[2].RoleVal).Title(ViewBag.Roles[2])

  }))

The for loop does not work with either the columns.Bound or the template. It results in an out of range error. When stepping into this code it works fine but it is afterwards that the error occurs.
Exception Details: System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

Source Error:

Line 31:     for (int c = 0; c < ViewBag.RoleCount; c++)
Line 32:     {
Line 33:columns.Template(@<text>@item.Roles[c].RoleVal.ToString()</text>).Title(ViewBag.Roles[c]);
Line 34:       //columns.Bound(r => r.Roles[c].RoleVal).Title(ViewBag.Roles[c]);
Line 35:     }


When I comment out the for loop and uncomment the columns.Bound lines it works perfectly with the attached result. Obviously this is not a solution for me as it is dynamic and I do not know how many columns there will be. Why does the for loop not work for this?



Regards
Tyler  

6 Answers, 1 is accepted

Sort by
0
Rosen
Telerik team
answered on 15 Feb 2016, 10:00 AM

Hello Tyler,

The cause for the error is how the C# captures scope variable. In the code you have pasted, the c variable value is incremented thus all of the expression used in the column Bound method will point to the last value of the c. In order to correct this you should use a local variable which will hold the exact value of the c at the point of creation of the Bound method. Similar to the following:

for (int c = 0; c < ViewBag.RoleCount; c++)
{
  var idx = c;
  columns.Bound(r => r.Roles[idx].RoleVal).Title(ViewBag.Roles[c]);
}

Regards,
Rosen
Telerik
 
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
 
0
Ruairi
Top achievements
Rank 1
answered on 18 Feb 2016, 09:13 AM

Thank you Rosen. That works perfectly.

I am having a problem with binding to the ClientTemplate. If I don't use a template the data binds fine with "true" and "false" for the Boolean values. If I use a ClientTemplate to show the values as a checkbox the values don't show on the grid.

for (int c = 0; c < ViewBag.RoleCount; c++)
{
var idx = c;
columns.Bound(r => r.Roles[idx].RoleVal)
.ClientTemplate("#<input type='checkbox' #= RoleVal ? checked='checked' : '' # disabled='disabled' ></input>#")
.Title(ViewBag.Roles[c]);
}

Would appreciate your help.

Tyler

0
Rosen
Telerik team
answered on 18 Feb 2016, 04:51 PM

Hello Tyler,

I guess the it does not work due to incorrect template. The hashes designate code expression, thus you should not wrap the entire markup with them.

"<input type='checkbox' #= RoleVal ? checked='checked' : '' # disabled='disabled' ></input>"

Information on Kendo templates can be found here. And information about Column's ClientTemplate is located here.

Regards,
Rosen
Telerik
 
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
 
0
Ruairi
Top achievements
Rank 1
answered on 19 Feb 2016, 12:21 PM

Rosen,

You are absolutely right, I shouldn't have those hashes in. However I have tried it as you suggested and numerous other ways. It doesn't seem to bind to the RoleVal in the ClientTemplate. I have checkboxes elsewhere in grids with no problem. The difference here I think is that they are bound to a list. I have read the documentation and numerous posts and cannot seem to figure a way to bind to the clientTemplate. Can you point me in the right direction? Is it even possible given the fact that the model is essentially dynamic?

Appreciate your help.

 

Tyler

0
Accepted
Rosen
Telerik team
answered on 22 Feb 2016, 09:28 AM

Hello Tyler,

In order to access the same value as with the column, you should use the same "path" as the one used in the Column.Bound configuration. Something similar to the following:

"<input type='checkbox' #= Roles[" + idx + "].RoleVal ? 'checked=checked' : '' # disabled='disabled' ></input>"

Regards,
Rosen
Telerik
 
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
 
0
Ruairi
Top achievements
Rank 1
answered on 22 Feb 2016, 02:21 PM
Thank you Rosen, works perfectly.
Tags
Grid
Asked by
Ruairi
Top achievements
Rank 1
Answers by
Rosen
Telerik team
Ruairi
Top achievements
Rank 1
Share this question
or