feat(module: table): enable to reload with an outside query model (#2129)

* feat/ApplyPredefinedQueryModel: add opportunity to serialize/deserialize QueryModel and apply to Table with ITable.ReloadData(QueryModel queryModel) method; fix current selected value in 'PageSize / page' selection (value was not updated in case using ReloadData(PageIndex, PageSize) method)

* feat/applyPredefinedQueryModel: implement System.Text.Json instead Newtonsoft.Json for serializing/deserializing QueryModel

* feat/applyPredefinedQueryModel: add minor change

* feat/applyPredefinedQueryModel: add method for converting from JsonElement to object type

* feat/applyPredefinedQueryModel: add demo file for save and load table configuration

* feature/applyPredefinedQueryModel: add minor change

* feat/applyPredefinedQueryModel: prevent applying before not saved configuration

* fix sorter restore

* reest data before reload data

* fix test

Co-authored-by: Ana Nikolasevic <23nikolasevic@gmail.com>
Co-authored-by: ElderJames <shunjiey@hotmail.com>
This commit is contained in:
AnaNikolasevic 2022-03-04 16:47:19 +01:00 committed by James Yeung
parent ab939b927f
commit 21a076dff5
15 changed files with 532 additions and 32 deletions

View File

@ -0,0 +1,67 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
namespace AntDesign.Core.Helpers
{
public static class JsonElementHelper<TValue>
{
static Type _columnDataType;
static JsonElementHelper()
{
_columnDataType = THelper.GetUnderlyingType<TValue>();
}
public static object GetValue(JsonElement jsonElement)
{
if (_columnDataType == typeof(DateTime))
return jsonElement.GetDateTime();
else if (_columnDataType.IsEnum)
{
if (jsonElement.ValueKind == JsonValueKind.Number)
return Enum.Parse(THelper.GetUnderlyingType<TValue>(), jsonElement.GetInt32().ToString());
else
return Enum.Parse(THelper.GetUnderlyingType<TValue>(), jsonElement.GetString());
}
else if (_columnDataType == typeof(byte))
return jsonElement.GetByte();
else if (_columnDataType == typeof(decimal))
return jsonElement.GetDecimal();
else if (_columnDataType == typeof(double))
return jsonElement.GetDouble();
else if (_columnDataType == typeof(short))
return jsonElement.GetInt16();
else if (_columnDataType == typeof(int))
return jsonElement.GetInt32();
else if (_columnDataType == typeof(long))
return jsonElement.GetInt64();
else if (_columnDataType == typeof(sbyte))
return jsonElement.GetSByte();
else if (_columnDataType == typeof(float))
return jsonElement.GetSingle();
else if (_columnDataType == typeof(ushort))
return jsonElement.GetUInt16();
else if (_columnDataType == typeof(uint))
return jsonElement.GetUInt32();
else if (_columnDataType == typeof(ulong))
return jsonElement.GetUInt64();
else if (_columnDataType == typeof(Guid))
return jsonElement.GetGuid();
else if (_columnDataType == typeof(bool))
{
if (jsonElement.ValueKind == JsonValueKind.True)
return true;
else
return false;
}
else
return jsonElement.GetString();
}
}
}

View File

@ -25,6 +25,7 @@
Size="@(IsSmall ? "small" : "default")"
Class="@($"{prefixCls}-size-changer")"
DefaultValue="@(PageSize > 0 ? PageSize : pageSizeOptions[0])"
@bind-Value="@PageSize"
BoundaryAdjustMode="@TriggerBoundaryAdjustMode.InView"
OnSelectedItemChanged="@(i => {if (ChangeSize.HasDelegate)ChangeSize.InvokeAsync(i);})">
<SelectOptions>

View File

@ -8,6 +8,8 @@ using System.Reflection;
using AntDesign.Internal;
using AntDesign.TableModels;
using Microsoft.AspNetCore.Components;
using System.Text.Json;
using AntDesign.Core.Helpers;
namespace AntDesign
{
@ -194,7 +196,7 @@ namespace AntDesign
if (Sortable && GetFieldExpression != null)
{
SortModel = new SortModel<TData>(GetFieldExpression, FieldName, SorterMultiple, DefaultSortOrder, SorterCompare);
SortModel = new SortModel<TData>(this, GetFieldExpression, FieldName, SorterMultiple, DefaultSortOrder, SorterCompare);
}
}
else if (IsBody)
@ -283,7 +285,7 @@ namespace AntDesign
if (IsHeader)
{
FilterModel = _filterable && _filters?.Any(x => x.Selected) == true ?
new FilterModel<TData>(GetFieldExpression, FieldName, OnFilter, _filters.Where(x => x.Selected).ToList(), _columnFilterType) :
new FilterModel<TData>(this, GetFieldExpression, FieldName, OnFilter, _filters.Where(x => x.Selected).ToList(), _columnFilterType) :
null;
}
}
@ -394,7 +396,7 @@ namespace AntDesign
});
}
_hasFilterSelected = _filters?.Any(x => x.Selected) == true;
FilterModel = _hasFilterSelected ? new FilterModel<TData>(GetFieldExpression, FieldName, OnFilter, _filters.Where(x => x.Selected).ToList(), _columnFilterType) : null;
FilterModel = _hasFilterSelected ? new FilterModel<TData>(this, GetFieldExpression, FieldName, OnFilter, _filters.Where(x => x.Selected).ToList(), _columnFilterType) : null;
Table?.ReloadAndInvokeChange();
}
@ -446,5 +448,40 @@ namespace AntDesign
{
_filters = new List<TableFilter>() { GetNewFilter() };
}
void IFieldColumn.ClearFilters() => ResetFilters();
void IFieldColumn.SetFilterModel(ITableFilterModel filterModel)
{
foreach (var filter in filterModel.Filters)
{
if (filter.Value is JsonElement)
{
filter.Value = JsonElementHelper<TData>.GetValue((JsonElement)filter.Value);
}
}
if (_columnFilterType == TableFilterType.List)
{
foreach (var filter in filterModel.Filters.Where(filter => filterModel.Filters.Any(x => x.Value == filter.Value)))
{
filter.Selected = true;
}
}
else
{
_filters = filterModel.Filters;
}
FilterModel = new FilterModel<TData>(this, GetFieldExpression, FieldName, OnFilter, _filters.Where(x => x.Selected).ToList(), _columnFilterType);
_hasFilterSelected = true;
}
void IFieldColumn.SetSortModel(ITableSortModel sortModel)
{
SortModel = new SortModel<TData>(this, GetFieldExpression, FieldName, SorterMultiple, SortDirection.Parse(sortModel.Sort), SorterCompare);
this.SetSorter(SortDirection.Parse(sortModel.Sort));
}
}
}

View File

@ -21,5 +21,11 @@ namespace AntDesign
public ITableFilterModel FilterModel { get; }
internal void ClearSorter();
internal void ClearFilters();
internal void SetFilterModel(ITableFilterModel filterModel);
internal void SetSortModel(ITableSortModel sortModel);
}
}

View File

@ -9,6 +9,10 @@ namespace AntDesign
void ReloadData(int? pageIndex, int? pageSize = null);
void ReloadData(QueryModel queryModel);
void ResetData();
QueryModel GetQueryModel();
void SetSelection(string[] keys);

View File

@ -166,6 +166,8 @@ namespace AntDesign
private IList<SummaryRow> _summaryRows;
private IFieldColumn[] _fieldColumns;
private bool _hasInitialized;
private bool _waitingDataSourceReload;
private bool _waitingReloadAndInvokeChange;
@ -223,12 +225,16 @@ namespace AntDesign
return;
}
_fieldColumns = ColumnContext.HeaderColumns.Where(x => x is IFieldColumn field && field.FieldName is not null).Cast<IFieldColumn>().ToArray();
ReloadAndInvokeChange();
_hasInitialized = true;
}
public void ReloadData()
{
ResetData();
PageIndex = 1;
FlushCache();
@ -238,6 +244,8 @@ namespace AntDesign
public void ReloadData(int? pageIndex, int? pageSize = null)
{
ResetData();
ChangePageIndex(pageIndex ?? 1);
ChangePageSize(pageSize ?? PageSize);
@ -246,7 +254,58 @@ namespace AntDesign
this.ReloadAndInvokeChange();
}
public QueryModel GetQueryModel() => BuildQueryModel();
public void ReloadData(QueryModel queryModel)
{
ResetData();
if (queryModel is not null)
{
ChangePageIndex(queryModel.PageIndex);
ChangePageSize(queryModel.PageSize);
FlushCache();
foreach (var sorter in queryModel.SortModel)
{
var fieldColumn = _fieldColumns[sorter.ColumnIndex];
fieldColumn.SetSortModel(sorter);
}
foreach (var filter in queryModel.FilterModel)
{
var fieldColumn = _fieldColumns[filter.ColumnIndex];
fieldColumn.SetFilterModel(filter);
}
this.ReloadAndInvokeChange();
}
}
public void ResetData()
{
ChangePageIndex(1);
ChangePageSize(PageSize);
FlushCache();
foreach (var col in ColumnContext.HeaderColumns)
{
if (col is IFieldColumn fieldColumn)
{
if (fieldColumn.SortModel != null)
{
fieldColumn.ClearSorter();
}
if (fieldColumn.FilterModel != null)
{
fieldColumn.ClearFilters();
}
}
}
}
public QueryModel GetQueryModel() => BuildQueryModel().Clone() as QueryModel;
private QueryModel<TItem> BuildQueryModel()
{

View File

@ -6,6 +6,8 @@ using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace AntDesign
{
@ -25,10 +27,36 @@ namespace AntDesign
{
this.Selected = selected;
}
public TableFilter()
{
}
#if NET5_0_OR_GREATER
[JsonConstructor]
#endif
public TableFilter(string text, object value, bool selected, TableFilterCompareOperator filterCompareOperator, TableFilterCondition filterCondition)
{
this.Text = text;
this.Value = value;
this.Selected = selected;
this.FilterCompareOperator = filterCompareOperator;
this.FilterCondition = filterCondition;
}
}
public class TableFilter<TValue> : TableFilter
{
public TableFilter()
{
}
#if NET5_0_OR_GREATER
[JsonConstructor]
#endif
public TableFilter(string text, object value, bool selected, TableFilterCompareOperator filterCompareOperator, TableFilterCondition filterCondition) : base(text, value, selected, filterCompareOperator, filterCondition)
{
}
new public TValue Value { get => (TValue)(base.Value ?? default(TValue)); set => base.Value = value; }
}

View File

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.Json.Serialization;
using AntDesign.FilterExpression;
namespace AntDesign.TableModels
@ -15,19 +16,33 @@ namespace AntDesign.TableModels
{
public string FieldName { get; }
public IEnumerable<string> SelectedValues { get; set; }
public IEnumerable<string> SelectedValues { get; }
public IList<TableFilter> Filters { get; }
public Expression<Func<TField, TField, bool>> OnFilter { get; set; }
private readonly FilterExpressionResolver<TField> _filterExpressionResolver = new FilterExpressionResolver<TField>();
public int ColumnIndex => _columnIndex;
private LambdaExpression _getFieldExpression;
private readonly FilterExpressionResolver<TField> _filterExpressionResolver = new FilterExpressionResolver<TField>();
private TableFilterType FilterType { get; set; } = TableFilterType.List;
public FilterModel(LambdaExpression getFieldExpression, string fieldName, Expression<Func<TField, TField, bool>> onFilter, IList<TableFilter> filters, TableFilterType filterType)
private LambdaExpression _getFieldExpression;
private int _columnIndex;
#if NET5_0_OR_GREATER
[JsonConstructor]
#endif
public FilterModel(int columnIndex, string fieldName, IEnumerable<string> selectedValues, IList<TableFilter> filters)
{
this.FieldName = fieldName;
this.SelectedValues = selectedValues;
this.Filters = filters;
this._columnIndex = columnIndex;
}
public FilterModel(IFieldColumn column, LambdaExpression getFieldExpression, string fieldName, Expression<Func<TField, TField, bool>> onFilter, IList<TableFilter> filters, TableFilterType filterType)
{
this._getFieldExpression = getFieldExpression;
this.FieldName = fieldName;
@ -42,6 +57,7 @@ namespace AntDesign.TableModels
this.SelectedValues = filters.Select(x => x.Value?.ToString());
this.Filters = filters;
this.FilterType = filterType;
this._columnIndex = column.ColIndex;
}
public IQueryable<TItem> FilterList<TItem>(IQueryable<TItem> source)
@ -108,9 +124,6 @@ namespace AntDesign.TableModels
{
return source.Where(Expression.Lambda<Func<TItem, bool>>(lambda, sourceExpression));
}
}
}
}

View File

@ -9,6 +9,8 @@ namespace AntDesign.TableModels
{
public string FieldName { get; }
public int ColumnIndex { get; }
public IEnumerable<string> SelectedValues { get; }
public IList<TableFilter> Filters { get; }

View File

@ -1,8 +1,9 @@
using System.Linq;
using System;
using System.Linq;
namespace AntDesign.TableModels
{
public interface ITableSortModel
public interface ITableSortModel : ICloneable
{
public string Sort { get; }
@ -10,6 +11,8 @@ namespace AntDesign.TableModels
public string FieldName { get; }
public int ColumnIndex { get; }
internal SortDirection SortDirection { get; }
internal void SetSortDirection(SortDirection sortDirection);

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
@ -29,14 +30,32 @@ namespace AntDesign.TableModels
this.SortModel = new List<ITableSortModel>();
this.FilterModel = new List<ITableFilterModel>();
}
#if NET5_0_OR_GREATER
[JsonConstructor]
#endif
public QueryModel(int pageIndex, int pageSize, IList<ITableSortModel> sortModel, IList<ITableFilterModel> filterModel)
{
this.PageIndex = pageIndex;
this.PageSize = pageSize;
this.SortModel = sortModel;
this.FilterModel = filterModel;
}
}
public class QueryModel<TItem> : QueryModel
public class QueryModel<TItem> : QueryModel, ICloneable
{
internal QueryModel(int pageIndex, int pageSize) : base(pageIndex, pageSize)
{
}
#if NET5_0_OR_GREATER
[JsonConstructor]
#endif
public QueryModel(int pageIndex, int pageSize, IList<ITableSortModel> sortModel, IList<ITableFilterModel> filterModel) : base(pageIndex, pageSize, sortModel, filterModel)
{
}
internal void AddSortModel(ITableSortModel model)
{
SortModel.Add(model);
@ -63,5 +82,12 @@ namespace AntDesign.TableModels
}
public IQueryable<TItem> CurrentPagedRecords(IQueryable<TItem> query) => query.Skip(OffsetRecords).Take(PageSize);
public object Clone()
{
var sorters = this.SortModel.Select(x => x.Clone() as ITableSortModel).ToList();
var filters = this.FilterModel.ToList();
return new QueryModel<TItem>(PageIndex, PageSize, sorters, filters);
}
}
}

View File

@ -1,14 +1,12 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using AntDesign.Internal;
using System.Text.Json.Serialization;
namespace AntDesign.TableModels
{
public class SortModel<TField> : ITableSortModel, IComparer<TField>
public class SortModel<TField> : ITableSortModel, IComparer<TField>, ICloneable
{
public int Priority { get; }
@ -18,21 +16,38 @@ namespace AntDesign.TableModels
SortDirection ITableSortModel.SortDirection => _sortDirection;
public int ColumnIndex => _columnIndex;
private readonly Func<TField, TField, int> _comparer;
private SortDirection _sortDirection;
private LambdaExpression _getFieldExpression;
public SortModel(LambdaExpression getFieldExpression, string fieldName, int priority, SortDirection defaultSortOrder, Func<TField, TField, int> comparer)
private int _columnIndex;
public SortModel(IFieldColumn column, LambdaExpression getFieldExpression, string fieldName, int priority, SortDirection defaultSortOrder, Func<TField, TField, int> comparer)
{
this.Priority = priority;
this._columnIndex = column.ColIndex;
this._getFieldExpression = getFieldExpression;
this.FieldName = fieldName;
this._comparer = comparer;
this._sortDirection = defaultSortOrder ?? SortDirection.None;
}
#if NET5_0_OR_GREATER
[JsonConstructor]
#endif
public SortModel(int columnIndex, int priority, string fieldName, string sort)
{
this.Priority = priority;
this._columnIndex = columnIndex;
this.FieldName = fieldName;
this._sortDirection = SortDirection.Parse(sort);
}
void ITableSortModel.SetSortDirection(SortDirection sortDirection)
{
_sortDirection = sortDirection;
@ -62,5 +77,10 @@ namespace AntDesign.TableModels
{
return _comparer?.Invoke(x, y) ?? 0;
}
public object Clone()
{
return new SortModel<TField>(_columnIndex, Priority, FieldName, Sort);
}
}
}

View File

@ -0,0 +1,220 @@
<Button @onclick="SaveTable">SAVE</Button>
<Button @onclick="LoadTable">LOAD</Button>
<Button @onclick="SaveTableWithJson">SAVE JSON</Button>
<Button @onclick="LoadTableWithJson">LOAD JSON</Button>
<Button @onclick="ResetTable">RESET</Button>
<Table DataSource="data" OnChange="OnChange" TItem="Data" @ref="Table" >
<Column TData="int"
@bind-Field="context.Number"
Sortable
Filterable />
<Column TData="Guid"
@bind-Field="context.Id"
Sortable
Filterable />
<Column TData="string"
@bind-Field="context.Name"
SorterCompare="@((a,b)=> string.Compare(a,b))"
SortDirections="new[] { SortDirection.Descending }"
Filterable />
<Column TData="string"
DataIndex="Address"
SorterCompare="@((a,b)=> string.Compare(a,b))"
SortDirections="new[] { SortDirection.Descending, SortDirection.Ascending }"
Filterable />
<Column TData="DateTime"
@bind-Field="context.BirthDate"
Format="yyyy/MM/dd"
Sortable
Filterable />
<Column TData="bool"
@bind-Field="context.IsActive"
Sortable
Filterable />
<Column TData="Gender"
@bind-Field="context.Gender"
Sortable
Filterable />
<Column TData="Hobbies?"
@bind-Field="context.Hobbies"
Sortable
Filterable />
</Table>
@using AntDesign.TableModels;
@using System.Text.Json;
@using System;
@using System.Text.Json.Serialization;
@code {
class Data
{
public Data(int number, string name, string address, DateTime birthDate, bool isActive, Gender gender, Hobbies? hobbies)
{
Number = number;
Id = Guid.NewGuid();
Name = name;
Address = address;
BirthDate = birthDate;
IsActive = isActive;
Gender = gender;
Hobbies = hobbies;
}
public int Number { get; set; }
public Guid Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public DateTime BirthDate { get; set; }
public bool IsActive { get; set; }
public Gender Gender { get; set; }
public Hobbies? Hobbies { get; set; }
}
enum Gender
{
Male,
Female
}
[Flags]
enum Hobbies
{
Reading = 1,
Sport = 2,
Cooking = 4
}
Table<Data> Table;
QueryModel SavedQueryModel;
string SavedQueryModelJson;
void OnChange(QueryModel<Data> query)
{
Console.WriteLine(JsonSerializer.Serialize(query));
}
void ResetTable()
{
Table.ResetData();
}
void SaveTable()
{
SavedQueryModel = Table.GetQueryModel();
}
void LoadTable()
{
if (SavedQueryModel is not null)
Table.ReloadData(SavedQueryModel);
}
void SaveTableWithJson()
{
SavedQueryModelJson = JsonSerializer.Serialize(Table.GetQueryModel());
}
void LoadTableWithJson()
{
if (SavedQueryModelJson is not null)
{
var settings = new JsonSerializerOptions();
settings.Converters.Add(new SortModelConverter());
settings.Converters.Add(new FilterModelConverter());
QueryModel<Data> queryModel = JsonSerializer.Deserialize<QueryModel<Data>>(SavedQueryModelJson, settings);
Table.ReloadData(queryModel);
}
}
public class FilterModelConverter : JsonConverter<ITableFilterModel>
{
public override ITableFilterModel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return JsonSerializer.Deserialize<FilterModel<string>>(ref reader, options);
}
public override void Write(Utf8JsonWriter writer, ITableFilterModel value, JsonSerializerOptions options)
{
}
}
public class SortModelConverter : JsonConverter<ITableSortModel>
{
public override ITableSortModel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return JsonSerializer.Deserialize<SortModel<string>>(ref reader, options);
}
public override void Write(Utf8JsonWriter writer, ITableSortModel value, JsonSerializerOptions options)
{
}
}
Data[] data =
{
new(1, "John Sunny","New York No. 1 Lake Park",new DateTime(1980,1,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Reading),
new(2, "Sara Green","London No. 1 Lake Park",new DateTime(1983,12,1),true,Gender.Female, Hobbies.Sport),
new(3, "White Miss", "Sidney No. 1 Lake Park",new DateTime(1977,11,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(4, "Sunny Red","London No. 2 Lake Park",new DateTime(1985,1,1),false,Gender.Male,null),
new(5, "John Brown","New York No. 1 Lake Park",new DateTime(1980,1,5),true,Gender.Male,Hobbies.Cooking | Hobbies.Reading),
new(6, "Sara Green","London No. 1 Lake Park",new DateTime(1983,12,1),true,Gender.Female,Hobbies.Reading | Hobbies.Sport),
new(7, "Miss Black", "Sidney No. 1 Lake Park",new DateTime(1977,1,5),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(8, "Jim Red","London No. 2 Lake Park",new DateTime(1987,1,1),false,Gender.Male,null),
new(9, "White Sunny","New York No. 1 Lake Park",new DateTime(1981,1,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Reading),
new(10, "Sara Green","London No. 1 Lake Park",new DateTime(1983,12,8),true,Gender.Female,Hobbies.Sport),
new(11, "Joe Black", "Sidney No. 1 Lake Park",new DateTime(1977,11,9),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(12, "Jim Red","London No. 2 Lake Park",new DateTime(1985,1,10),false,Gender.Male,null),
new(13, "Sunny Brown","New York No. 1 Lake Park",new DateTime(1980,12,12),true,Gender.Male,Hobbies.Cooking | Hobbies.Reading),
new(14, "Sara Sunny","London No. 1 Lake Park",new DateTime(1983,2,1),true,Gender.Female,Hobbies.Reading),
new(15, "Joe White", "Sidney No. 1 Lake Park",new DateTime(1977,8,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(16, "Jim Miss","London No. 2 Lake Park",new DateTime(1985,1,7),false,Gender.Male,null),
new(17, "John Brown","New York No. 1 Lake Park",new DateTime(1980,9,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Reading),
new(18, "Sara Green","London No. 1 Lake Park",new DateTime(1983,4,4),true,Gender.Female,Hobbies.Reading | Hobbies.Sport),
new(19, "Joe Black", "Sidney No. 1 Lake Park",new DateTime(1977,3,4),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(20, "Jim Red","London No. 2 Lake Park",new DateTime(1985,8,8),false,Gender.Male,null),
new(21, "John Brown","New York No. 1 Lake Park",new DateTime(1980,7,7),true,Gender.Male,Hobbies.Cooking | Hobbies.Reading),
new(22, "White Green","London No. 1 Lake Park",new DateTime(1993,12,1),true,Gender.Female,Hobbies.Reading | Hobbies.Sport),
new(23, "Joe Black", "Sidney No. 1 Lake Park",new DateTime(1997,11,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(24, "Jim Red","London No. 2 Lake Park",new DateTime(1995,1,1),false,Gender.Male,null),
new(25, "Sara Green","London No. 1 Lake Park",new DateTime(1984,12,1),true,Gender.Female,Hobbies.Reading | Hobbies.Sport),
new(26, "Joe Anna", "Sidney No. 1 Lake Park",new DateTime(1975,11,1),true,Gender.Male,Hobbies.Sport),
new(27, "Jim Red","London No. 2 Lake Park",new DateTime(1986,1,1),false,Gender.Male,null),
new(28, "John White","New York No. 1 Lake Park",new DateTime(1987,1,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Reading),
new(29, "Anna Green","London No. 1 Lake Park",new DateTime(1988,12,1),true,Gender.Female, Hobbies.Sport),
new(30, "Sunny Black", "Sidney No. 1 Lake Park",new DateTime(1979,11,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(31, "Jim Red","London No. 2 Lake Park",new DateTime(1985,1,1),false,Gender.Male,null),
new(32, "Miss Brown","New York No. 1 Lake Park",new DateTime(1989,1,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Reading),
new(33, "Sara Green","London No. 1 Lake Park",new DateTime(1989,12,1),true,Gender.Female,Hobbies.Reading ),
new(34, "Joe Black", "Sidney No. 1 Lake Park",new DateTime(1979,11,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(35, "White Red","London No. 2 Lake Park",new DateTime(1989,1,1),false,Gender.Male,null),
new(36, "John Anna","New York No. 1 Lake Park",new DateTime(1980,1,1),true,Gender.Male,Hobbies.Cooking),
new(37, "Anna Sunny","London No. 1 Lake Park",new DateTime(1983,12,1),true,Gender.Female,Hobbies.Reading | Hobbies.Sport),
new(38, "Joe Black", "Sidney No. 1 Lake Park",new DateTime(1977,11,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(39, "Jim Red","London No. 2 Lake Park",new DateTime(1985,1,1),false,Gender.Male,null),
new(40, "John Brown","New York No. 1 Lake Park",new DateTime(1980,1,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Reading),
new(41, "Sara Green","London No. 1 Lake Park",new DateTime(1983,12,1),true,Gender.Female,Hobbies.Reading | Hobbies.Sport),
new(42, "Anna White", "Sidney No. 1 Lake Park",new DateTime(1977,11,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(43, "Jim Red","London No. 2 Lake Park",new DateTime(1985,1,1),false,Gender.Male,null),
new(44, "John Miss","New York No. 1 Lake Park",new DateTime(1980,1,1),true,Gender.Male, Hobbies.Reading),
new(45, "Miss Green","London No. 1 Lake Park",new DateTime(1983,12,1),true,Gender.Female,Hobbies.Reading | Hobbies.Sport),
new(46, "Joe Black", "Sidney No. 1 Lake Park",new DateTime(1977,11,1),true,Gender.Male,Hobbies.Cooking ),
new(47, "Jim Sunny","London No. 2 Lake Park",new DateTime(1985,1,1),false,Gender.Male,null),
new(48, "White Anna","New York No. 1 Lake Park",new DateTime(1980,1,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Reading),
new(49, "Sara Green","London No. 1 Lake Park",new DateTime(1983,12,1),true,Gender.Female, Hobbies.Sport),
new(50, "Joe Anna", "Sidney No. 1 Lake Park",new DateTime(1977,11,1),true,Gender.Male,Hobbies.Cooking | Hobbies.Sport),
new(51, "Miss Red","London No. 2 Lake Park",new DateTime(1985,1,1),false,Gender.Male,null),
};
}

View File

@ -0,0 +1,14 @@
---
order: 32
title:
en-US: Restore query state
zh-CN: 恢复筛选状态
---
## zh-CN
任何带有“过滤器”、“排序”、“页面大小”和“页面索引”的筛选状态都可以保存,并可以在以后重新恢复 Table 的分页、排序和过滤器。
## en-US
Every table configuration with 'Filter', 'Sort', 'PageSize' and 'PageIndex' can be saved and later re-applied. Also applied sorting and filters can be reseted by one click.

View File

@ -16,23 +16,23 @@
var cut = Render(@<CheckboxGroup Options="@plainOptions"/>);
cut.MarkupMatches(
@<div class="ant-checkbox-group" id:ignore>
<label class="ant-checkbox-wrapper" id:ignore>
<label class="ant-checkbox-wrapper" for:ignore>
<span class="ant-checkbox-group-item ant-checkbox">
<input type="checkbox" value="Apple" class="ant-checkbox-input">
<input type="checkbox" value="Apple" class="ant-checkbox-input" id:ignore>
<span class="ant-checkbox-inner"></span>
</span>
<span><span>Apple</span></span>
</label>
<label class="ant-checkbox-wrapper" id:ignore>
<label class="ant-checkbox-wrapper" for:ignore>
<span class="ant-checkbox-group-item ant-checkbox">
<input type="checkbox" value="Pear" class="ant-checkbox-input">
<input type="checkbox" value="Pear" class="ant-checkbox-input" id:ignore>
<span class="ant-checkbox-inner"></span>
</span>
<span><span>Pear</span></span>
</label>
<label class="ant-checkbox-wrapper" id:ignore>
<label class="ant-checkbox-wrapper" for:ignore>
<span class="ant-checkbox-group-item ant-checkbox">
<input type="checkbox" value="Orange" class="ant-checkbox-input">
<input type="checkbox" value="Orange" class="ant-checkbox-input" id:ignore>
<span class="ant-checkbox-inner"></span>
</span>
<span><span>Orange</span></span>
@ -46,23 +46,23 @@
var cut = Render(@<CheckboxGroup Options="@options"/>);
cut.MarkupMatches(
@<div class="ant-checkbox-group" id:ignore>
<label class="ant-checkbox-wrapper" id:ignore>
<label class="ant-checkbox-wrapper" for:ignore>
<span class="ant-checkbox-group-item ant-checkbox">
<input type="checkbox" value="Apple" class="ant-checkbox-input">
<input type="checkbox" value="Apple" class="ant-checkbox-input" id:ignore>
<span class="ant-checkbox-inner"></span>
</span>
<span><span>Apple</span></span>
</label>
<label class="ant-checkbox-wrapper" id:ignore>
<label class="ant-checkbox-wrapper" for:ignore>
<span class="ant-checkbox-group-item ant-checkbox">
<input type="checkbox" value="Pear" class="ant-checkbox-input">
<input type="checkbox" value="Pear" class="ant-checkbox-input" id:ignore>
<span class="ant-checkbox-inner"></span>
</span>
<span><span>Pear</span></span>
</label>
<label class="ant-checkbox-wrapper" id:ignore>
<label class="ant-checkbox-wrapper" for:ignore>
<span class="ant-checkbox-group-item ant-checkbox">
<input type="checkbox" value="Orange" class="ant-checkbox-input">
<input type="checkbox" value="Orange" class="ant-checkbox-input" id:ignore>
<span class="ant-checkbox-inner"></span>
</span>
<span><span>Orange</span></span>