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

Grid with columns tied to a Dictionary (Sorting & Dropdown Menu)

6 Answers 1192 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Siarhei
Top achievements
Rank 1
Siarhei asked on 26 Jan 2016, 04:04 AM

There are several topics on this forum regarding linking Grid columns to Dictionary properties. I've managed to do just that, but these columns are missing sorting and dropdown menu.

My model represents an issue from issue tracking system that may have very different fields depending on particular configuration. I can't see it feasible to define each possible property for my model class and the only logical solution is to have direct properties for most common fields and have a Dictionary for custom fields.

 

I'm using Kendo.MVC version 2016.1.112 in MVC 6 / .NET 5 project (which currently doesn't support server-side binding as far as I understand - rendering some solutions posted on this forum inapplicable). Browser is Chrome, but it doesn't seem the issue relates to browser version.

 

My model class is as follows:

public class Issue
{
    public string Key { get; set; }
    public string Summary { get; set; }
    public string Status { get; set; }
    public string StatusType { get; set; }
    public DateTime? Created { get; set; }
    public DateTime? LastUpdated { get; set; }
 
    public Dictionary<string, object> CustomProperties { get; set; } = new Dictionary<string, object>();
}

 

The Grid is then defined in View's *.cshtml file as this:

@(Html.Kendo().Grid<JIRAReports.Models.Issue>()
  .Name("grid")
  .HtmlAttributes(new { style = "margin-top: 10px;" })
  .DataSource(dataSource => dataSource.Ajax()
                                      .Sort(sort => sort.Add("LastUpdated").Ascending())
                                      .Read(read => read.Action("JiraIssues_Read", "Reports"))
                                      .PageSize(15)
 
              )
  .Columns(columns =>
  {
    columns.Bound(issue => issue.Key).Width(120).HtmlAttributes(new { style = "white-space: nowrap;" })
      .ClientTemplate($"<a href=\"{baseIssueUrl}#=Key#\" target=\"_blank\">#=Key#</a>");
    columns.Bound(issue => issue.Status).Width(150)
      .ClientTemplate(statusColumnTemplate);
    columns.Bound(issue => issue.Summary).HtmlAttributes(new { style = "white-space: nowrap;" });
    columns.Bound(issue => issue.LastUpdated).Width(180).HtmlAttributes(new { style = "white-space: nowrap;" })
      .Title("Last Updated").Format("{0:M/d/yyyy (ddd)}");
    //Adding custom properties
    columns.Template("#:CustomProperties['CustomProperty1']#").Title("Custom Property 1");
    columns.Template("#:CustomProperties['CustomProperty2']#").Title("Custom Property 2").Hidden();
  })
  .Pageable(config => config.PageSizes(new[] { 10, 15, 25, 100 })
                            .Refresh(true))
  .Sortable(config => config.AllowUnsort(false).SortMode(GridSortMode.MultipleColumn))
  .Scrollable(config => config.Height("895px"))
  .Resizable(config => config.Columns(true))
  .ClientDetailTemplateId("item-template")
  .ToolBar(tools => tools.Custom().Text("Expand All").Name("ExpandAll"))
  .ToolBar(tools => tools.Custom().Text("Collapse All").Name("CollapseAll"))
  .NoRecords()
  .ColumnMenu()
  .Reorderable(config => config.Columns(true))
  .Deferred()

 

The resulting grid is rendered as on the screenshot attached. You can see there is no dropdown next to columns linked to Dictionary's items, they are not sortable, but these columns do appear in dropdowns for other columns so they can be shown/hidden. But sorting on them is absolutely required.

 

Please suggest a solution. There must be a way to link to less structured data or indexer property, especially since all we need is to display it in read-only mode.

6 Answers, 1 is accepted

Sort by
0
Siarhei
Top achievements
Rank 1
answered on 26 Jan 2016, 04:31 AM

A little bit more information after trying something suggested in post: http://www.telerik.com/forums/dictionary-keys-binding

 

First of all, suggested first option for Ajax binding to call "columns.Template(o => { }).ClientTemplate(...)" doesn't work as there is no Template method with lambda expression.

 

Another suggested option to use "dynamic" as a model was somewhat successful. The code is like this:

@(Html.Kendo().Grid<dynamic>()
  .Name("grid")
  .HtmlAttributes(new { style = "margin-top: 10px;" })
  .DataSource(dataSource => dataSource.Ajax()
                                      .Sort(sort => sort.Add("LastUpdated").Ascending())
                                      .Read(read => read.Action("JiraIssues_Read", "Reports"))
                                      .PageSize(15)
 
              )
  .Columns(columns =>
  {
    columns.Bound("Key").Width(120).HtmlAttributes(new { style = "white-space: nowrap;" })
      .ClientTemplate($"<a href=\"{jiraUrl}#=Key#\" target=\"_blank\">#=Key#</a>");
    columns.Bound("Status").Width(150)
      .ClientTemplate(statusColumnTemplate);
    columns.Bound("Summary").HtmlAttributes(new { style = "white-space: nowrap;" });
    columns.Bound(typeof(DateTime), "LastUpdated").Width(180).HtmlAttributes(new { style = "white-space: nowrap;" })
      .Title("Last Updated").Format("{0:M/d/yyyy (ddd)}");
    //Adding custom properties
    columns.Bound("CustomProperties['CustomProperty1']").Title("Custom Property 1");
    columns.Bound("CustomProperties['CustomProperty2']").Title("Custom Property 2").Hidden();
  })

 

The custom properties can now be sorted on and I can see how I can achieve quite a bit more with dynamic as a model (albeit with some convenience lost). However, it seem like with dynamic option all data is treated as string. For example, I could not make the LastUpdated field display as a Date using Format method (even after calling Bound with specific type of DateTime).

 

Help is much appreciated.

0
Siarhei
Top achievements
Rank 1
answered on 26 Jan 2016, 03:41 PM

OK, seems the following is working for formatting DateTime columns when grid uses dynamic model:

columns.Bound("LastUpdated").Width(180).HtmlAttributes(new { style = "white-space: nowrap;" })
  .ClientTemplate("#=kendo.toString(kendo.parseDate(LastUpdated), 'M/dd/yyyy (ddd)')#")
  .Title("Last Updated");

Still, please let me know if the solutions in my posts are optimal or there is some better way of doing this.

0
Alexander Popov
Telerik team
answered on 28 Jan 2016, 12:43 PM
Hello Siarhei,

The reason for this behavior is the inability of the Kendo UI DataSource to resolve the data type of complex objects' properties. As a result, the date strings are not parsed into Date objects. The same happens when using a dynamic model and not explicitly specifying the data type. Here is an example how this can be done using a Custom DataSource: 
.DataSource(d => d
    .Custom()
       ...
    .Schema(s => s.
        Model(m => {
            m.Field("SomeDate", typeof(DateTime));
        })
    )
)
The approach where the date string is parsed manually in a template will work as well, however that way you lose the ability to sort and filter the column properly.

Regards,
Alexander Popov
Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Siarhei
Top achievements
Rank 1
answered on 28 Jan 2016, 05:28 PM

Alexander,

 

Thanks for the suggestion. I would like to first comment on your last sentence. So far I haven't got any issues with sorting on such columns and I can't see how it could be an issue given the fact that sorting is done server-side and Controller's method receives proper DataSourceRequest parameter.

 

Regarding Custom datasource, I did manage to make it work ...somewhat. First of all it took few tries to get it right, the following resource has proved helpful: http://docs.telerik.com/kendo-ui/aspnet-mvc/custom-datasource

 

So far I have the following setup that I'm having an issue with:

.DataSource(dataSource => dataSource.Custom()
                                    .Type("aspnetmvc-ajax")
                                    .PageSize(15)
                                    .ServerPaging(true)
                                    .ServerSorting(true)
                                    .ServerFiltering(true)
                                    .Transport(transport => transport
                                        .Read(read => read.Action("JiraIssues_Read", "Reports"))
                                    )
                                    .Schema(schema => schema
                                      .Data("Data")
                                      .Total("Total")
                                      .Errors("Errors")
                                      .Model(model => {
                                        model.Field("LastUpdated", typeof(DateTime));
                                        model.Field("Resolved", typeof(DateTime));
                                        model.Field("CustomProperties['Target Completion']", typeof(DateTime));
                                      })
                                    )

 

Columns are then added by reading CustomProperties configuration and set in the foreach loop with the following code:

var columnBuilder = columns.Bound($"CustomProperties['{fieldConfig.Name}']");
columnBuilder.Title(fieldConfig.Name);
if (fieldConfig.IsHidden)
{
  columnBuilder.Hidden();
}
if (fieldConfig.Type == "Date")
{
  columnBuilder.Format("{0:M/dd/yyyy (ddd)}");
}

I know for a fact that this code adds "CustomProperties['Target Completion']" column with Format as specified, but the column value is not formatted as expected and in default format, e.g. "2016-01-20T00:00:00". Meanwhile "LastUpdated" and "Resolved" columns display as expected, with Format applied.

 

When looking at generated page source, I see that column is defined with "field" of "CustomProperties[\u0027Target Completion\u0027]" and model defines "CustomProperties['Target Completion']":{"type":"date"}.

Not sure if difference between \u0027 and ' causes this or grid can't apply formatting to complex objects' fields even if model specifically sets it. If the latter is the case, I don't see why it makes sense to use Custom DataSource as it makes code longer.

 

Please let me know if there is a way to properly support DateTime type for columns for complex fields like CustomProperties['...'].

0
Accepted
Alexander Popov
Telerik team
answered on 01 Feb 2016, 03:00 PM
Hello,

You are correct, the sorting should not be affected. In such cases we usually recommend flattening the ViewModel, although using the "from" option to create a new field is also an option. For example: 
@(Html.Kendo().Grid<dynamic>()
    .Name("Grid")
    .Columns(columns =>
    {
        columns.Bound(typeof(DateTime), "SomeDate").Width(200).Format("{0:g}");
    })
    .Filterable()
    .Sortable()
    .DataSource(dataSource => dataSource
        .Custom()
        ....
        .Schema(s =>
        {
            s.Data("Data");
            s.Model(m =>
            {
                m.Field("SomeDate", typeof(DateTime)).Parse(@<text>function(dateString) { return kendo.parseDate(dateString); }</text>).From("SomeObject.SomeDate");
            });
        })
        .Transport(t=>{
            t.Read(a => a.Action("Read", "Grid").Type(HttpVerbs.Post));
            })
        )
    )


Regards,
Alexander Popov
Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Siarhei
Top achievements
Rank 1
answered on 01 Feb 2016, 03:42 PM
Alexander, thanks for the suggestion, it's great to find out about other techniques Grid supports. For now though I'm going to stick with the initial solution, but will keep these other options in mind should I run into issues.
Tags
Grid
Asked by
Siarhei
Top achievements
Rank 1
Answers by
Siarhei
Top achievements
Rank 1
Alexander Popov
Telerik team
Share this question
or