Kendo Grid Dynamic Columns

If the number and type of columns are not known at design time but are at runtime then the columns can be dynamically built up with standard razor coding.

UPDATE: I have made a working example. It can be found on Github at https://github.com/CodeBeastie/Presentation
Its mixed in with some code I did for a presentation but look for the GridDynamic example. Some time in the coming weeks I will make its own project along with some more complex examples.

Example:
Normally you will be setting your Kendo grid with a set of known columns but in some cases you may not know the columns you will be showing. You may wish the user to be able to select the columns so the grid will need to cater for this varying columns.
One way of doing this is to create a class that contains a list of column details. This list could be setup depending on the users settings.
When creating the Kendo Grid the construction of the columns loops through these details and builds the desired columns. The following code shows an example of this construction of columns.

Simple example:

@(Html.Kendo()
    .Grid<MyGridViewModel>()
    .Name("kgridA")
    .Columns(columns => {
        foreach (MyColumnSettings col in Model.MyColumns) {
            columns.Bound(col.PropertyName).Title(col.Title)
    }

The key point to note is the column bound needs at minimum the name of the property in the grid model it is going to bind to. It has to be given and must match exactly the name of the field.

The class for the column settings would be

public class MyColumnSettings {  
    /// <summary>Title used in header.</summary>
    public string Title { get; set; }

    /// <summary>Property name in row viewmodel that the column is bound to.</summary>
    public string PropertyName { get; set; }
}

A list code be built as follows which passes the necessary details to the grid column construction. This is fixed but the list could be created from settings stored in file/db etc.

vm.GridColumns = new List<MyColumnSettings> {  
  new MyColumnSettings { Title="Animal Name", PropertyName="Name"},
  new MyColumnSettings { Title="Animal Type", PropertyName="AnimalType"}
};

The above is a simple example but more complex columns can be created. I have used it in more complex grid edit scenarios where dropdowns and autocomplete text entry boxes where also included.

@(Html.Kendo()
    .Grid<MyGridViewModel>()
    .Name("kgridA")
    .Columns(columns => {
        //fixed columns
        columns.Bound(p => p.Id).Hidden();
        columns.Bound(p => p.ProjectId).Hidden();

        foreach (MyColumnSettings col in Model.MyColumns) {
            if (col.UseAutoComplete) {
                columns.Bound(col.PropertyName).Title(col.Title)
                    .EditorTemplateName("GridAutoComplete")
                    .EditorViewData(new { aclist = col.AutoList })
                    .Width(col.Width);
            }else {
                if (col.IsList) {
                    columns.ForeignKey(col.PropertyName, col.SelList, "Id", "ItemText")
                        .Width(col.Width).Title(col.Title);
                }else {
                    columns.Bound(col.PropertyName).Title(col.Title).Width(col.Width);
                }
            }
        }
    })

In the example above I cater for edit fields that are using Kendo autocompletes and Kendo dropdowns so column class indicates the type and also passes the necessary lists for these.
Additional information like the title and widths and colours could all be passed.

To expand on the above example with the classes involved

My view would have a model passed to as such

@model AttributeEditorViewModel

This model would contain various data but will include a list of the column settings.

//Model passed to the view
public class AttributeEditorViewModel {  
    public int ProjectId { get; set; }
    public List<MyColumnSettings> AttrColumns { get; set; }
    public List<string> Abbreviations { get; set; }
}

The columns details may be as simple as the Title and property or can hold details on the column type i.e. indicate that it a dropdown and provide the dropdown contents.

//settings for each column
public class MyColumnSettings {  
    /// <summary>Column number on the grid.</summary>
    public int ColNum { get; set; }

    public int AttrId { get; set; }

    /// <summary>Title used in header.</summary>
    public string Title { get; set; }

    /// <summary>Property name in row viewmodel that the column is bound to.</summary>
    public string PropertyName { get; set; }

    /// <summary>True if attribute is a list.</summary>
    public bool IsList { get; set; }

    /// <summary>True if a autocomplete is to be used instaed of a dropdown. (Allows adding to lists)</summary>
    public bool UseAutoComplete { get; set; }

    /// <summary>True if field can be edited</summary>
    public bool Editable { get; set; }

    /// <summary>System type of the property being edited. Required for grid edtiable setting.</summary>
    public Type ColType { get; set; }

    /// <summary>Width to set the column</summary>
    public int Width { get; set; }

    /// <summary>Holds list of id,text for user to select from. For non Adding attribute lists.</summary>
    public List<idtextPairViewModel> SelList { get; set; }

    /// <summary>Holds list of text for autocompletion to work with. For text and lists that user can add to.</summary>
    public List<string> AutoList { get; set; }
}

The grid itself is bound to its own model which in my case is something like

    public class MyGridViewModel {
        public int Id { get; set; }

        //Fixed editing fields
        public string Name { get; set; }
        public string Description { get; set; }

        //Columns functionality will change
        public int A01 { get; set; }
        public int L01 { get; set; }
        public string S01 { get; set; }

        public int A02 { get; set; }
        public int L02 { get; set; }
        public string S02 { get; set; }

        public int A03 { get; set; }
        public int L03 { get; set; }
        public string S03 { get; set; }

        public int A04 { get; set; }
        public int L04 { get; set; }
        public string S04 { get; set; }

        public int A05 { get; set; }
        public int L05 { get; set; }
        public string S05 { get; set; }

The fields A01,L01,S01 usage vary depending on how the user/project setup has been configured. At runtime the MyColumnSettings is built depending on the settings and that will determine column appears - whether it is a text entry, readonly, dropdown etc.
I used a fixed class fields to make it simple but you could dynamically create the class at runtime.
See also
Kendo Grid Dynamic Columns with ExpandoObjects

Notes
Client side column adding/removing is not supported. (hiding is though)
Dynamically adjusting columns at runtime is not support (but hacks appear to be possible. Lost my references to these unfortunately)


Above referring to version
Telerik Kendo UI Professional Q1 2015
Telerik UI for ASP.NET MVC Q1 2015


comments powered by Disqus