Skip to content

Commit aee5463

Browse files
committed
AJAX grid now preserves client state between requests (page, pageSize, sorting, filtering etc.). TODO: Add PreserveGridState() method to ALL relevant grids in the backend.
1 parent a95d180 commit aee5463

11 files changed

Lines changed: 159 additions & 129 deletions

File tree

src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ public GridModel<GoogleProductModel> GetGridModel(GridCommand command, string se
540540
var textInfo = CultureInfo.InvariantCulture.TextInfo;
541541

542542
// there's no way to share a context instance across repositories which makes GoogleProductObjectContext pretty useless here.
543-
// so let's fallback to good ole sql... by the way, fastest possible paged data query ever.
543+
// so let's fallback to good old sql... by the way, fastest possible paged data query ever.
544544

545545
var whereClause = new StringBuilder("(NOT ([t2].[Deleted] = 1)) AND ([t2].[VisibleIndividually] = 1)");
546546

src/Presentation/SmartStore.Web.Framework/Extensions/Extensions.cs

Lines changed: 100 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Reflection;
5+
using System.Web.Routing;
56
using System.Web.Mvc;
67
using SmartStore.Core;
78
using SmartStore.Core.Domain.Catalog;
@@ -17,9 +18,92 @@
1718

1819
namespace SmartStore.Web.Framework
1920
{
20-
public static class Extensions
21+
22+
[Serializable]
23+
public class GridStateInfo
24+
{
25+
public GridState State { get; set; }
26+
public string Path { get; set; }
27+
}
28+
29+
30+
public static class Extensions
2131
{
22-
public static IEnumerable<T> ForCommand<T>(this IEnumerable<T> current, GridCommand command)
32+
33+
public static GridBuilder<T> PreserveGridState<T>(this GridBuilder<T> builder) where T : class
34+
{
35+
var grid = builder.ToComponent();
36+
37+
if (!grid.DataBinding.Ajax.Enabled)
38+
return builder;
39+
40+
if (grid.Id.IsEmpty())
41+
throw new SmartException("A grid with preservable state must have a valid Id or Name");
42+
43+
var urlHelper = new UrlHelper(grid.ViewContext.RequestContext);
44+
45+
grid.AppendCssClass("grid-preservestate");
46+
grid.HtmlAttributes.Add("data-statepreserver-href", urlHelper.Action("SetGridState", "Common", new { area = "admin" }));
47+
48+
// Try restore state from a previous request
49+
var info = (GridStateInfo)grid.ViewContext.TempData["GridState." + grid.Id];
50+
if (info != null && info.Path.Equals(grid.ViewContext.HttpContext.Request.Path, StringComparison.OrdinalIgnoreCase))
51+
{
52+
// persist again for the next request
53+
grid.ViewContext.TempData["GridState." + grid.Id] = info;
54+
55+
var state = info.State;
56+
var command = GridCommand.Parse(state.Page, state.Size, state.OrderBy, state.GroupBy, state.Filter);
57+
if (command.PageSize > 0)
58+
{
59+
grid.Paging.PageSize = command.PageSize;
60+
}
61+
if (command.Page > 0)
62+
{
63+
grid.Paging.CurrentPage = command.Page;
64+
}
65+
66+
foreach (var sort in command.SortDescriptors)
67+
{
68+
var existingSort = grid.Sorting.OrderBy.FirstOrDefault(x => x.Member.IsCaseInsensitiveEqual(sort.Member));
69+
if (existingSort != null)
70+
{
71+
grid.Sorting.OrderBy.Remove(existingSort);
72+
}
73+
grid.Sorting.OrderBy.Add(sort);
74+
}
75+
76+
if (command.GroupDescriptors.Any())
77+
{
78+
grid.Grouping.Groups.AddRange(command.GroupDescriptors);
79+
}
80+
81+
foreach (var group in command.GroupDescriptors)
82+
{
83+
var existingGroup = grid.Grouping.Groups.FirstOrDefault(x => x.Member.IsCaseInsensitiveEqual(group.Member));
84+
if (existingGroup != null)
85+
{
86+
grid.Grouping.Groups.Remove(existingGroup);
87+
}
88+
grid.Grouping.Groups.Add(group);
89+
}
90+
91+
foreach (var filter in command.FilterDescriptors)
92+
{
93+
var compositeFilter = filter as CompositeFilterDescriptor;
94+
if (compositeFilter == null)
95+
{
96+
compositeFilter = new CompositeFilterDescriptor { LogicalOperator = FilterCompositionLogicalOperator.And };
97+
compositeFilter.FilterDescriptors.Add(filter);
98+
}
99+
grid.Filtering.Filters.Add(compositeFilter);
100+
}
101+
}
102+
103+
return builder;
104+
}
105+
106+
public static IEnumerable<T> ForCommand<T>(this IEnumerable<T> current, GridCommand command)
23107
{
24108
var queryable = current.AsQueryable() as IQueryable;
25109
if (command.FilterDescriptors.Any())
@@ -40,20 +124,20 @@ public static IEnumerable<T> ForCommand<T>(this IEnumerable<T> current, GridComm
40124
temporarySortDescriptors.Add(sortDescriptor);
41125
}
42126

43-
if (command.GroupDescriptors.Any())
44-
{
45-
command.GroupDescriptors.Reverse().Each(groupDescriptor =>
46-
{
47-
SortDescriptor sortDescriptor = new SortDescriptor
48-
{
49-
Member = groupDescriptor.Member,
50-
SortDirection = groupDescriptor.SortDirection
51-
};
52-
53-
command.SortDescriptors.Insert(0, sortDescriptor);
54-
temporarySortDescriptors.Add(sortDescriptor);
55-
});
56-
}
127+
if (command.GroupDescriptors.Any())
128+
{
129+
command.GroupDescriptors.Reverse().Each(groupDescriptor =>
130+
{
131+
SortDescriptor sortDescriptor = new SortDescriptor
132+
{
133+
Member = groupDescriptor.Member,
134+
SortDirection = groupDescriptor.SortDirection
135+
};
136+
137+
command.SortDescriptors.Insert(0, sortDescriptor);
138+
temporarySortDescriptors.Add(sortDescriptor);
139+
});
140+
}
57141

58142
if (command.SortDescriptors.Any())
59143
{

src/Presentation/SmartStore.Web.Framework/UI/ScaffoldExtensions.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77

88
namespace SmartStore.Web.Framework.UI
99
{
10-
/// <summary>
11-
/// <remarks>codehint: sm-add</remarks>
12-
/// </summary>
10+
1311
public static class ScaffoldExtensions
1412
{
1513
public static string SymbolForBool<T>(this HtmlHelper<T> helper, string boolFieldName)

src/Presentation/SmartStore.Web/Administration/Content/admin.less

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,12 @@ td.adminData > input[type="checkbox"] {
423423
}
424424

425425
.t-grid-filter {
426-
margin-top: -1.6em;
426+
margin: 0;
427+
padding: 0;
428+
position: absolute;
429+
right: 4px;
430+
top: 50%;
431+
margin-top: -8px;
427432
}
428433

429434
.t-link:hover {
@@ -434,12 +439,13 @@ td.adminData > input[type="checkbox"] {
434439
font-size: 12px;
435440
text-transform: uppercase;
436441
font-weight: bold !important;
437-
padding-top: 0.6em !important;
438-
padding-bottom: 0.6em !important;
442+
padding: 0 !important;
443+
position: relative;
439444
}
440445

441446
.t-grid-header .t-header .t-link {
442-
width: 100%;
447+
margin: 0;
448+
padding: 0.6em;
443449
}
444450

445451
.t-grid-pager,
@@ -504,10 +510,6 @@ label.forcheckbox {
504510
display: inline;
505511
}
506512

507-
a:hover {
508-
font-weight: normal;
509-
}
510-
511513
/* SECTION HEADERS */
512514
.section-title {
513515
border-bottom: solid 3px #dfdfdf;

src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
using SmartStore.Core.Domain.Common;
3434
using System.Reflection;
3535
using Autofac;
36+
using SmartStore.Web.Framework;
3637

3738
namespace SmartStore.Admin.Controllers
3839
{
@@ -287,6 +288,17 @@ public JsonResult SetSelectedTab(string navId, string tabId, string path)
287288
return Json(new { Success = true });
288289
}
289290

291+
[HttpPost]
292+
public JsonResult SetGridState(string gridId, GridState state, string path)
293+
{
294+
if (gridId.HasValue() && state != null && path.HasValue())
295+
{
296+
var info = new GridStateInfo { State = state, Path = path };
297+
TempData["GridState." + gridId] = info;
298+
}
299+
return Json(new { Success = true });
300+
}
301+
290302
public ActionResult SystemInfo()
291303
{
292304
var model = new SystemInfoModel();

src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ public ActionResult Resources(int languageId, GridCommand command)
336336
.GetResourceValues(languageId, true)
337337
.OrderBy(x => x.Key)
338338
.Where(x => x.Key != "!!___EOF___!!" && x.Value != null)
339-
.Select(x => new LanguageResourceModel()
339+
.Select(x => new LanguageResourceModel
340340
{
341341
LanguageId = languageId,
342342
LanguageName = language.Name,

src/Presentation/SmartStore.Web/Administration/Views/Category/List.cshtml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
})
7676
.Pageable(settings => settings.Total(Model.Categories.Total).PageSize(gridPageSize).Position(GridPagerPosition.Both))
7777
.DataBinding(dataBinding => dataBinding.Ajax().Select("List", "Category"))
78+
.PreserveGridState()
7879
.EnableCustomBinding(true))
7980
</td>
8081
</tr>

src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@
207207
.Pageable(settings => settings.Total(Model.Products.Total).PageSize(Model.GridPageSize).Position(GridPagerPosition.Both))
208208
.DataBinding(dataBinding => dataBinding.Ajax().Select("ProductList", "Product"))
209209
.ClientEvents(events => events.OnDataBinding("productsGrid_onDataBinding").OnDataBound("productsGrid_onDataBound"))
210-
.EnableCustomBinding(true))
210+
.EnableCustomBinding(true)
211+
.PreserveGridState())
211212
</td>
212213
</tr>
213214
</table>

src/Presentation/SmartStore.Web/Content/bootstrap/custom/telerik/telerik.smartstore.less

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,9 @@
230230
background-color: #f7f7f7;
231231
}
232232

233+
.t-grouping-header {
234+
text-shadow: none;
235+
padding: 0.6em;
236+
}
237+
233238

src/Presentation/SmartStore.Web/Scripts/smartstore.common.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,32 @@
126126
}
127127
});
128128

129+
// Telerik grid smart AJAX state preserving
130+
$('.t-grid.grid-preservestate').on('dataBound', function (e) {
131+
var grid = $(this).data("tGrid"),
132+
href = $(this).data("statepreserver-href");
133+
134+
console.log("GridLoad", grid);
135+
136+
if (href) {
137+
$.ajax({
138+
type: "POST",
139+
url: href,
140+
async: true,
141+
data: {
142+
gridId: $(this).attr('id'),
143+
path: location.pathname,
144+
page: grid.currentPage,
145+
size: grid.pageSize,
146+
orderBy: grid.orderBy,
147+
groupBy: grid.groupBy,
148+
filter: grid.filterBy
149+
},
150+
global: false
151+
});
152+
}
153+
});
154+
129155
// AJAX tabs
130156
$('.nav a[data-ajax-url]').on('show', function (e) {
131157
var newTab = $(e.target),

0 commit comments

Comments
 (0)