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

Kendo UI Server Bound Grid - UIHint and DisplayTemplate

4 Answers 1116 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Peter
Top achievements
Rank 1
Peter asked on 23 Aug 2013, 12:30 PM
Is it possible to make use of the UIHint attribute on a model property such as -
[Display(Name = "Days Late"), UIHint("_DaysToDate"), ReadOnly(true)]
 
public
int? DaysLate

     get; set
}
In order to specify a DisplayTemplate partial as a Template for grid data?

We have a fairly generic grid HTML helper method that uses model attributes whilst binding -
private static GridBuilder<dynamic> CreateDynamicGrid<TBaseViewModelType>(this HtmlHelper helper, string gridName, string provisioningControllerName, string formActionName = "Edit",
bool checkboxRowSelect = false)
{
var type =
typeof(TBaseViewModelType);
var modelProperties =
type.GetProperties().Where(p => p.IsScaffoldable()).ToList();

var
identityProperty = type.GetProperty("Id");

var idFieldName =
string.Empty;

if (identityProperty != null)
{
idFieldName =
identityProperty.Name;
}
 
return
helper.Kendo().Grid<dynamic>()
 .Name(gridName)
.Columns(columns
=> {
columns.Template(t => t).ClientTemplate("<input
class='select-row' type='checkbox' />").HeaderTemplate(t =>
"<input class='select-all-rows' type='checkbox' />").Width(40).Visible(checkboxRowSelect);
columns.Template(t =>
t).ClientTemplate(helper.ActionLink(VisionWebResources.Action_More, formActionName,
provisioningControllerName, new { id = string.Format("#= {0} #", idFieldName) },
null).ToHtmlString()).Visible(identityProperty != null).Width("4em");
modelProperties.ForEach(p =>
columns.Bound(p.GetPrevailingType(), p.Name).Format(p.GetFormatString()).HtmlAttributes(p.GetHtmlAttributes()).Width(InitialColumnWidth));
})
 .DataSource(ds => ds.Ajax()
.PageSize(15) 
.Read(r => r.Action("Read", provisioningControllerName))
 
.Model(model =>
{
model.Id(
"Id");
foreach (var property in
modelProperties) {model.Field(property.Name, property.GetPrevailingType));
 }
 })
)
.Editable(ed =>
ed.Enabled(false))
.Events(events => events.DataBound(
"function() { "
+
 
"if (typeof (gridDataBound) === 'function') { gridDataBound(); }"  +
"}").Change("function() { " +
"
if (typeof (gridFocusedRowChanged) ===
'function') { gridFocusedRowChanged(); }" +
 "
}"))
.Filterable()
.HtmlAttributes(new { @class = "grid" })
.Navigatable()
.Pageable(pages
=>
{
    pages.PageSizes(
new[] { 15, 25, 40 });
    pages.Refresh(
true);
//Provides a button to refresh the current grid page
 })
.Resizable(resize => resize.Columns(true))
.Scrollable(scrollable =>
scrollable.Height(425))
.Selectable(selectable =>
selectable.Mode(GridSelectionMode.Single))
.Sortable(sortable =>
sortable.AllowUnsort(false));
 }

The grid has a dynamic model which is based partially on a fixed ViewModel and partially on dynamic fields which are created and managed by the users within the database (and thus cannot be known in advance). As such the binding is programmatic and not directly to a model. The dynamic fields do not require a display template, I simply wanted to provide some context around our approach.

The line that builds up the columns from the fixed ViewModel is-

modelProperties.ForEach(p => columns.Bound(p.GetPrevailingType(), p.Name).Format(p.GetFormatString()).HtmlAttributes(p.GetHtmlAttributes()).Width(InitialColumnWidth));

Can I add the "ClientTemplate" method to load a partial based on the UIHint value for the property, perhaps use @Html.DisplayFor(), or must this be explicit text?

4 Answers, 1 is accepted

Sort by
0
Accepted
Daniel
Telerik team
answered on 27 Aug 2013, 11:43 AM
Hello,

The ClientTemplate method accepts only a string so you should convert the DisplayTemplate to a string by using the ToString or ToHtmlString methods. Since the model is dynamic the DisplayFor helper cannot be used so you should use the Display helper and get the display template name as demonstrated in this article e.g.

public static class PropertyInfoExtensions
{
    public static string GetUIHint(this System.Reflection.PropertyInfo property)
    {
        return ModelMetadataProviders.
            Current.GetMetadataForProperty(null, property.DeclaringType,
            property.Name).TemplateHint;
    }
}
columns.Bound(p.GetPrevailingType(), p.Name)
    .ClientTemplate(Html.Display(p.Name, p.GetUIHint()).ToHtmlString())
Note that since the grid is configured for Ajax binding, you should still use the template syntax to get the field values in the display template. Regards,
Daniel
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Peter
Top achievements
Rank 1
answered on 27 Aug 2013, 03:14 PM
This works very well, thank you.

For anyone else who is wanting to keep things generic, the ClientTemplate documentation all lists (http://docs.kendoui.com/getting-started/framework/templates/overview) the syntax as follows-
<div class="due-indicator"></div>
<span>#= DaysLate
#</span>
Clearly explicitly listing the field name like this makes the template anything but generic.

There is however an option that allows you to produce a generic Display Template, use the UI hint as described above, and get the field name within the partial view used as the template.

Using the TemplateInfo class there is a property HtmlFieldPrefix which the MSDN documentation (http://msdn.microsoft.com/en-us/library/system.web.mvc.templateinfo.htmlfieldprefix(v=vs.108).aspx) states "Gets or sets the HTML field prefix." - the field name bound to the template.

Altering the template to-
@{var fieldName = ViewData.TemplateInfo.HtmlFieldPrefix;}
 
<div class="due-indicator"></div>
<span>#= @fieldName #</span>
or
<div class="due-indicator"></div>
<span>#= @ ViewData.TemplateInfo.HtmlFieldPrefix #</span>
Produces a generic template that can be bound the appropriate column client side.
0
Manish
Top achievements
Rank 1
answered on 29 Oct 2013, 02:59 PM
Hi,

I am trying to follow this solution to specify template for complex type properties but it's just not working. Here is my code:
    public abstract class PreContractAgreementData : EntityData
    {
        public int Version { get; set; }
 
        [Display(Name = @"Reference Number", Description = @"Reference Number")]
        public string ReferenceNumber { get; set; }
 
        [Required]
        [MaxLength(ValidationRules.Agreement.Title_Length)]
        public string Title { get; set; }
 
        [Required]
        public DateTime? AgreementExecutionDate { get; set; }
 
        [Required]
        public AgreementStatus? Status { get; set; }
 
        [Required]
        public AgreementStage? Stage { get; set; }
 
        public AreaDirectorateData AreaDirectorate { get; set; }
}
@(Html.Kendo().Grid(Model.List)
.Name("createViewGrid")
.EnableCustomBinding(true)
.Columns(columns =>
    columns
        .Bound(typeof (CreateAgreementData), "AreaDirectorate")
        .ClientTemplate(Html.Display("AreaDirectorate", "EntityData").ToHtmlString()))
.DataSource(dataSource => dataSource
    .Ajax().Total(Model.TotalCount)
    .PageSize(20)
    .Model(model => model.Id(p => p.Id))
    .Events(events => events.RequestEnd("KendoRequestEndHandler"))
    .Events(events => events.Error("KendoErrorHandler")))
.Filterable(filterable => filterable.Extra(false))
.Sortable()
.Pageable(builder => builder.PageSizes(new[] { 20, 30, 40, 50 }))
.Resizable(s => s.Columns(true)))
@model Crossrail.AMS.Service.Data.AreaDirectorateData
 
<span>#=  @(Model != null ? Model.Id : 0)  #</span>

0
Daniel
Telerik team
answered on 31 Oct 2013, 05:48 PM
Hello,

You should use the Kendo template syntax in the Display Template when using Ajax binding:

<span>#= AreaDirectorateData != null ? AreaDirectorateData.Id : 0  #</span>
Regards,
Daniel
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Tags
Grid
Asked by
Peter
Top achievements
Rank 1
Answers by
Daniel
Telerik team
Peter
Top achievements
Rank 1
Manish
Top achievements
Rank 1
Share this question
or