Skip to content

Commit 8d7db45

Browse files
author
Not Bob
committed
Display Attribute Support
Replaced the stock reflection .GetProperties with an ordered properties that respects the Display(Order=) data annotations for easier ordering of columns. A reference to system.componentmodel.dataannotations had to be added to the project as well.
1 parent c1f126c commit 8d7db45

File tree

4 files changed

+129
-103
lines changed

4 files changed

+129
-103
lines changed
Lines changed: 67 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,68 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.ComponentModel;
4-
using System.Linq;
5-
using System.Linq.Expressions;
6-
using System.Reflection;
7-
using System.Text;
8-
using System.Web;
9-
using System.Web.Mvc;
10-
using System.Web.Mvc.Html;
11-
12-
namespace Mvc.JQuery.Datatables
13-
{
14-
public static class DataTablesHelper
15-
{
16-
17-
public static IHtmlString DataTableIncludes(this HtmlHelper helper, bool jqueryUi = false, bool filters = true, bool tableTools = true)
18-
{
19-
StringBuilder output = new StringBuilder();
20-
Action<string> addJs = s => output.AppendLine(@"<script src=""" + s + @""" type=""text/javascript""></script>");
21-
Action<string> addCss = s => output.AppendLine(@"<link type=""text/css"" href=""" + s + @""" rel=""stylesheet""/>");
22-
23-
addCss("/Content/DataTables/media/css/" + (jqueryUi ? ("jquery.dataTables_themeroller.css") : "jquery.dataTables.css"));
24-
addJs("/Content/DataTables/media/js/jquery.dataTables.js");
25-
if (filters) addJs("/Content/jquery.dataTables.columnFilter.js");
26-
if (tableTools)
27-
{
28-
addJs("/Content/DataTables/extras/TableTools/media/js/ZeroClipboard.js");
29-
addJs("/Content/DataTables/extras/TableTools/media/js/TableTools.js");
30-
addCss("/Content/DataTables/extras/TableTools/media/css/TableTools.css");
31-
}
32-
return helper.Raw(output.ToString());
33-
34-
}
35-
36-
public static DataTableVm DataTableVm<TController, TResult>(this HtmlHelper html, string id, Expression<Func<TController, DataTablesResult<TResult>>> exp, IEnumerable<ColDef> columns = null)
37-
{
38-
if (columns == null || !columns.Any())
39-
{
40-
var propInfos = typeof (TResult).GetProperties().Where(p => p.GetGetMethod() != null).ToList();
41-
var columnList = new List<ColDef>();
42-
foreach (var propertyInfo in propInfos)
43-
{
44-
var displayNameAttribute = (DisplayNameAttribute) propertyInfo.GetCustomAttributes(typeof (DisplayNameAttribute), false).FirstOrDefault();
45-
var displayName = displayNameAttribute == null ? propertyInfo.Name : displayNameAttribute.DisplayName;
46-
columnList.Add(new ColDef()
47-
{
48-
Name = propertyInfo.Name,
49-
DisplayName = displayName,
50-
Type = propertyInfo.PropertyType
51-
});
52-
}
53-
columns = columnList.ToArray();
54-
}
55-
56-
var mi = exp.MethodInfo();
57-
var controllerName = typeof(TController).Name;
58-
controllerName = controllerName.Substring(0, controllerName.LastIndexOf("Controller"));
59-
var urlHelper = new UrlHelper(html.ViewContext.RequestContext);
60-
var ajaxUrl = urlHelper.Action(mi.Name, controllerName);
61-
return new DataTableVm(id, ajaxUrl, columns);
62-
}
63-
64-
public static DataTableVm DataTableVm(this HtmlHelper html, string id, string ajaxUrl, params string[] columns)
65-
{
66-
return new DataTableVm(id, ajaxUrl, columns.Select(c => ColDef.Create(c, (string)null, typeof(string))));
67-
}
68-
}
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.Linq;
5+
using System.Linq.Expressions;
6+
using System.Reflection;
7+
using System.Text;
8+
using System.Web;
9+
using System.Web.Mvc;
10+
using System.Web.Mvc.Html;
11+
12+
namespace Mvc.JQuery.Datatables
13+
{
14+
public static class DataTablesHelper
15+
{
16+
public static IHtmlString DataTableIncludes(this HtmlHelper helper, bool jqueryUi = false, bool filters = true, bool tableTools = true)
17+
{
18+
StringBuilder output = new StringBuilder();
19+
Action<string> addJs = s => output.AppendLine(@"<script src=""" + s + @""" type=""text/javascript""></script>");
20+
Action<string> addCss = s => output.AppendLine(@"<link type=""text/css"" href=""" + s + @""" rel=""stylesheet""/>");
21+
22+
addCss("/Content/DataTables/media/css/" + (jqueryUi ? ("jquery.dataTables_themeroller.css") : "jquery.dataTables.css"));
23+
addJs("/Content/DataTables/media/js/jquery.dataTables.js");
24+
if (filters) addJs("/Content/jquery.dataTables.columnFilter.js");
25+
if (tableTools)
26+
{
27+
addJs("/Content/DataTables/extras/TableTools/media/js/ZeroClipboard.js");
28+
addJs("/Content/DataTables/extras/TableTools/media/js/TableTools.js");
29+
addCss("/Content/DataTables/extras/TableTools/media/css/TableTools.css");
30+
}
31+
return helper.Raw(output.ToString());
32+
}
33+
34+
public static DataTableVm DataTableVm<TController, TResult>(this HtmlHelper html, string id, Expression<Func<TController, DataTablesResult<TResult>>> exp, IEnumerable<ColDef> columns = null)
35+
{
36+
if (columns == null || !columns.Any())
37+
{
38+
//var propInfos = typeof (TResult).GetProperties().Where(p => p.GetGetMethod() != null).ToList();
39+
var propInfos = TypeExtensions.GetSortedProperties<TResult>();
40+
var columnList = new List<ColDef>();
41+
foreach (var propertyInfo in propInfos)
42+
{
43+
var displayNameAttribute = (DisplayNameAttribute)propertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), false).FirstOrDefault();
44+
var displayName = displayNameAttribute == null ? propertyInfo.Name : displayNameAttribute.DisplayName;
45+
columnList.Add(new ColDef()
46+
{
47+
Name = propertyInfo.Name,
48+
DisplayName = displayName,
49+
Type = propertyInfo.PropertyType
50+
});
51+
}
52+
columns = columnList.ToArray();
53+
}
54+
55+
var mi = exp.MethodInfo();
56+
var controllerName = typeof(TController).Name;
57+
controllerName = controllerName.Substring(0, controllerName.LastIndexOf("Controller"));
58+
var urlHelper = new UrlHelper(html.ViewContext.RequestContext);
59+
var ajaxUrl = urlHelper.Action(mi.Name, controllerName);
60+
return new DataTableVm(id, ajaxUrl, columns);
61+
}
62+
63+
public static DataTableVm DataTableVm(this HtmlHelper html, string id, string ajaxUrl, params string[] columns)
64+
{
65+
return new DataTableVm(id, ajaxUrl, columns.Select(c => ColDef.Create(c, (string)null, typeof(string))));
66+
}
67+
}
6968
}

Mvc.JQuery.Datatables/DataTablesResult.cs

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
using Mvc.JQuery.Datatables.DynamicLinq;
12
using System;
23
using System.Collections;
34
using System.Collections.Generic;
45
using System.Linq;
6+
using System.Reflection;
57
using System.Web;
68
using System.Web.Mvc;
7-
using Mvc.JQuery.Datatables.DynamicLinq;
89

910
namespace Mvc.JQuery.Datatables
1011
{
@@ -14,85 +15,85 @@ public static DataTablesResult<TRes> Create<T, TRes>(IQueryable<T> q, DataTables
1415
{
1516
return new DataTablesResult<T, TRes>(q, dataTableParam, transform);
1617
}
18+
1719
public static DataTablesResult<T> Create<T>(IQueryable<T> q, DataTablesParam dataTableParam)
1820
{
1921
return new DataTablesResult<T, T>(q, dataTableParam, t => t);
2022
}
2123

22-
public static DataTablesResult<T> CreateResultUsingEnumerable<T>(IEnumerable<T> q, DataTablesParam dataTableParam)
23-
{
24-
return new DataTablesResult<T, T>(q.AsQueryable(), dataTableParam, t => t);
25-
}
26-
2724
public static DataTablesResult Create(object queryable, DataTablesParam dataTableParam)
2825
{
29-
queryable = ((IEnumerable) queryable).AsQueryable();
26+
queryable = ((IEnumerable)queryable).AsQueryable();
3027
var s = "Create";
3128

3229
var openCreateMethod =
33-
typeof (DataTablesResult).GetMethods().Single(x => x.Name == s && x.GetGenericArguments().Count() == 1);
30+
typeof(DataTablesResult).GetMethods().Single(x => x.Name == s && x.GetGenericArguments().Count() == 1);
3431
var queryableType = queryable.GetType().GetGenericArguments()[0];
3532
var closedCreateMethod = openCreateMethod.MakeGenericMethod(queryableType);
36-
return (DataTablesResult) closedCreateMethod.Invoke(null, new[] {queryable, dataTableParam});
33+
return (DataTablesResult)closedCreateMethod.Invoke(null, new[] { queryable, dataTableParam });
3734
}
3835

36+
public static DataTablesResult<T> CreateResultUsingEnumerable<T>(IEnumerable<T> q, DataTablesParam dataTableParam)
37+
{
38+
return new DataTablesResult<T, T>(q.AsQueryable(), dataTableParam, t => t);
39+
}
3940
}
41+
4042
public class DataTablesResult<T> : DataTablesResult
4143
{
42-
4344
}
4445

45-
46-
4746
public class DataTablesResult<T, TRes> : DataTablesResult<TRes>
4847
{
48+
private static readonly List<PropertyTransformer> PropertyTransformers = new List<PropertyTransformer>()
49+
{
50+
Guard<DateTimeOffset>(dateTimeOffset => dateTimeOffset.ToLocalTime().ToString("g")),
51+
Guard<DateTime>(dateTime => dateTime.ToLocalTime().ToString("g")),
52+
Guard<IHtmlString>(s => s.ToHtmlString()),
53+
Guard<object>(o => (o ?? "").ToString())
54+
};
55+
4956
private readonly Func<T, TRes> _transform;
5057

5158
public DataTablesResult(IQueryable<T> q, DataTablesParam dataTableParam, Func<T, TRes> transform)
5259
{
53-
5460
_transform = transform;
55-
var properties = typeof(TRes).GetProperties();
61+
62+
//var properties = typeof(TRes).GetProperties();
63+
var properties = TypeExtensions.GetSortedProperties<TRes>();
5664

5765
var content = GetResults(q, dataTableParam, properties.Select(p => Tuple.Create(p.Name, (string)null, p.PropertyType)).ToArray());
5866
this.Data = content;
5967
this.JsonRequestBehavior = JsonRequestBehavior.DenyGet;
6068
}
6169

62-
static readonly List<PropertyTransformer> PropertyTransformers = new List<PropertyTransformer>()
63-
{
64-
Guard<DateTimeOffset>(dateTimeOffset => dateTimeOffset.ToLocalTime().ToString("g")),
65-
Guard<DateTime>(dateTime => dateTime.ToLocalTime().ToString("g")),
66-
Guard<IHtmlString>(s => s.ToHtmlString()),
67-
Guard<object>(o => (o ?? "").ToString())
68-
};
70+
public delegate object GuardedValueTransformer<TVal>(TVal value);
6971

7072
public delegate object PropertyTransformer(Type type, object value);
71-
public delegate object GuardedValueTransformer<TVal>(TVal value);
7273

73-
static PropertyTransformer Guard<TVal>(GuardedValueTransformer<TVal> transformer)
74+
public static void RegisterFilter<TVal>(GuardedValueTransformer<TVal> filter)
75+
{
76+
PropertyTransformers.Add(Guard<TVal>(filter));
77+
}
78+
79+
private static PropertyTransformer Guard<TVal>(GuardedValueTransformer<TVal> transformer)
7480
{
7581
return (t, v) =>
7682
{
7783
if (!typeof(TVal).IsAssignableFrom(t))
7884
{
7985
return null;
8086
}
81-
return transformer((TVal) v);
87+
return transformer((TVal)v);
8288
};
8389
}
84-
public static void RegisterFilter<TVal>(GuardedValueTransformer<TVal> filter)
85-
{
86-
PropertyTransformers.Add(Guard<TVal>(filter));
87-
}
90+
8891
private DataTablesData GetResults(IQueryable<T> data, DataTablesParam param, Tuple<string, string, Type>[] searchColumns)
8992
{
90-
9193
int totalRecords = data.Count(); //annoying this, as it causes an extra evaluation..
9294

9395
var filters = new DataTablesFilter();
9496

95-
9697
var filteredData = data.Select(_transform).AsQueryable();
9798
filteredData = filters.FilterPagingSortingSearch(param, filteredData, searchColumns).Cast<TRes>();
9899

@@ -102,13 +103,15 @@ private DataTablesData GetResults(IQueryable<T> data, DataTablesParam param, Tup
102103
page = page.Take(param.iDisplayLength);
103104
}
104105

105-
var type = typeof(TRes);
106-
var properties = type.GetProperties();
106+
//var type = typeof(TRes);
107+
//var propertiesOriginal = type.GetProperties();
108+
109+
var properties = TypeExtensions.GetSortedProperties<TRes>();
107110

108111
var transformedPage = from i in page
109-
let pairs = properties.Select(p => new {p.PropertyType, Value = (p.GetGetMethod().Invoke(i, null))})
110-
let values = pairs.Select(p => GetTransformedValue(p.PropertyType, p.Value))
111-
select values;
112+
let pairs = properties.Select(p => new { p.PropertyType, Value = (p.GetGetMethod().Invoke(i, null)) })
113+
let values = pairs.Select(p => GetTransformedValue(p.PropertyType, p.Value))
114+
select values;
112115

113116
var result = new DataTablesData
114117
{

Mvc.JQuery.Datatables/Mvc.JQuery.Datatables.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
3838
</Reference>
3939
<Reference Include="System" />
40+
<Reference Include="System.ComponentModel.DataAnnotations" />
4041
<Reference Include="System.Core" />
4142
<Reference Include="System.Web" />
4243
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
@@ -59,6 +60,7 @@
5960
<Compile Include="DynamicLinq\DynamicLinq.cs" />
6061
<Compile Include="Properties\AssemblyInfo.cs" />
6162
<Compile Include="StaticReflectionHelper.cs" />
63+
<Compile Include="TypeExtensions.cs" />
6264
</ItemGroup>
6365
<ItemGroup>
6466
<EmbeddedResource Include="..\Mvc.JQuery.Datatables.Templates\Views\Shared\DataTable.cshtml">
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel.DataAnnotations;
4+
using System.Linq;
5+
using System.Reflection;
6+
7+
public static class TypeExtensions
8+
{
9+
public static IEnumerable<PropertyInfo> GetSortedProperties(this Type t)
10+
{
11+
return from pi in t.GetProperties()
12+
let da = (DisplayAttribute)pi.GetCustomAttributes(typeof(DisplayAttribute), false).SingleOrDefault()
13+
let order = ((da != null && da.Order != 0) ? da.Order : int.MaxValue)
14+
orderby order
15+
select pi;
16+
}
17+
18+
public static IEnumerable<PropertyInfo> GetSortedProperties<T>()
19+
{
20+
return TypeExtensions.GetSortedProperties(typeof(T));
21+
}
22+
}

0 commit comments

Comments
 (0)