asp.net mvc - Telerik MVC Grid not grouping properly -
i'm using telerik mvc grid component render groupable grid populated via ajax. grid renders fine, sorting , paging works, ajax refresh works, when try grouping, rendering gets screwed up. attached screen caps of grid pre- , post-grouping.
the grid definition pretty straight-forward:
<div id="tabaccounts" class="tab_content"> @(html.telerik().grid<sharedsimpleaccountlistviewmodel>() .name("acctgrid") .columns(columns => { columns.bound(x => x.number) .headerhtmlattributes(new { @style = "text-align: center;" }) .htmlattributes(new { @style = "text-align: center;" }); columns.bound(x => x.providerorganizationfriendlyname) .title("provider"); columns.bound(x => x.name) .title("account name"); columns.bound(x => x.billinglocationname) .title("location"); }) .groupable() .databinding(db => db.ajax().select("customeraccounts", "customers", new { id = model.id })) .pageable(pager => pager.pagesize(50)) .sortable() ) </div>
the controller action straight-forward (i won't paste since it's retrieval repository). i'm using telerik default theme, there's no custom css , i've confirmed required scripts included in page.
inspecting html after grouping, appears there changes made table, it's not adding table row element group. here's html exists after grouping attempt:
<table cellspacing="0"> <colgroup> <col class="t-group-col"> <col><col><col><col> </colgroup> <thead class="t-grid-header"> <tr> <th class="t-group-cell t-header"> </th> <th style="text-align: center;" scope="col" class="t-header"> <a href="/customers/details/408?acctgrid-orderby=number-asc" class="t-link">number</a> </th> <th scope="col" class="t-header"> <a href="/customers/details/408?acctgrid-orderby=providerorganizationfriendlyname-asc" class="t-link">provider</a> </th> <th scope="col" class="t-header"> <a href="/customers/details/408?acctgrid-orderby=name-asc" class="t-link">account name</a> </th> <th scope="col" class="t-header t-last-header"> <a href="/customers/details/408?acctgrid-orderby=billinglocationname-asc" class="t-link">location</a> </th> </tr> </thead> <tbody> <tr> <td style="text-align: center;">00002</td> <td>acme</td> <td>test account 2 </td> <td class="t-last">location 2</td> </tr> <tr class="t-alt"> <td style="text-align: center;">00001</td> <td>3m</td> <td>test account 1</td> <td class="t-last">location 1</td> </tr> </tbody> </table>
any ideas might going on here?
the crux of issue here doing ajax binding wanted grouping , sorting. required manual sorting process sorted grouped column first, other sorted columns. grid takes care of setting group ui. bit of challenge me because project uses nhibernate orm robust service layer handles querying. ended getting grid work helper class looks this:
public static class telerikgridhelpers { public static ienumerable<aggregatefunctionsgroup> buildinnergroup<t, tobject>(ienumerable<tobject> group, func<tobject, t> groupselector, func<ienumerable<tobject>, ienumerable> innerselector) { return group.groupby(groupselector) .select(i => new aggregatefunctionsgroup { key = i.key, items = innerselector(i) }); } public static func<ienumerable<tobject>, ienumerable<aggregatefunctionsgroup>> buildgroup<t, tobject>(func<tobject, t> groupselector, func<ienumerable<tobject>, ienumerable<aggregatefunctionsgroup>> selectorbuilder) { var tempselector = selectorbuilder; return g => g.groupby(groupselector) .select(c => new aggregatefunctionsgroup { key = c.key, hassubgroups = true, items = tempselector.invoke(c).tolist() }); } public static ienumerable<aggregatefunctionsgroup> applygrouping<t>(iqueryable<t> data, ilist<groupdescriptor> groupdescriptors) { func<ienumerable<t>, ienumerable<aggregatefunctionsgroup>> selector = null; foreach (var descriptor in groupdescriptors.reverse()) { var tempdescriptor = descriptor; if (selector == null) selector = g => buildinnergroup(g.select(p => p), p => p.gettype().getproperty(tempdescriptor.member).getvalue(p, null), => i.tolist()); else selector = buildgroup(p => p.gettype().getproperty(tempdescriptor.member).getvalue(p, null), selector); } return selector != null ? selector.invoke(data).tolist() : null; } public static list<order> generateorderlist<t>(this t translator, gridcommand command) t : ipropertynametranslator { var orders = new list<order>(); // step 1 add grouping orders if (command.groupdescriptors.any()) orders.addrange(from descriptor in command.groupdescriptors let sortfield = translator.translatepropertytodomainproperty(descriptor.member) select descriptor.sortdirection == listsortdirection.ascending ? order.asc(sortfield) : order.desc(sortfield)); // sorting if (command.sortdescriptors.any()) orders.addrange(from descriptor in command.sortdescriptors.where(c => !command.groupdescriptors.where(g => g.member == c.member).any()) let sortfield = translator.translatepropertytodomainproperty(descriptor.member) select descriptor.sortdirection == listsortdirection.ascending ? order.asc(sortfield) : order.desc(sortfield)); return orders; } public static list<vieworder> generatevieworderlist<t>(this t translator, gridcommand command) t : ipropertynametranslator { var orders = new list<vieworder>(); // step 1 add grouping orders if (command.groupdescriptors.any()) orders.addrange(from descriptor in command.groupdescriptors let sortfield = translator.translatepropertytodomainproperty(descriptor.member) select new vieworder { propertyname = sortfield, ascending = descriptor.sortdirection == listsortdirection.ascending}); // sorting if (command.sortdescriptors.any()) orders.addrange(from descriptor in command.sortdescriptors.where(c => !command.groupdescriptors.where(g => g.member == c.member).any()) let sortfield = translator.translatepropertytodomainproperty(descriptor.member) select new vieworder { propertyname = sortfield, ascending = descriptor.sortdirection == listsortdirection.ascending }); return orders; } }
note i'm using viewmodels have flattened property names, if domain object has property of type address
, viewmodel might have property name of addressstreet
, addresscity
. ipropertytranslator
interface specifies translation process can go string sort member names in gridcommand
object domain expects.
the order
class in second-to-last method nhibernate order
. method used generate list of order
objects pass service layer when retrieve results. vieworder
utility class use in ui. still need refactor last 2 methods since repetitive.
here's example of how use helper class pull gridmodel
grid:
public gridmodel getallordersgrid(gridcommand command) { var svc = dependencyresolver.current.getservice<iorderservice>(); var propertytranslator = new ordersviewmodeltranslator(); var orders = propertytranslator.generateorderlist(command).tolist(); ifuturevalue<long> total; var orders = svc.findall(((command.page - 1) * command.pagesize), command.pagesize, orders, out total); var mapper = new mapper<domainorder, ordersviewmodel>(); var viewmodels = orders.select(mapper.maptoviewmodel); return command.groupdescriptors.any() ? new gridmodel { data = telerikgridhelpers.applygrouping(viewmodels.asqueryable(), command.groupdescriptors), total = convert.toint32(total.value) } : new gridmodel { data = viewmodels, total = convert.toint32(total.value) }; }
there's bit in there that's irrelevant whole question of grouping, it's real world example, maybe help.
Comments
Post a Comment