mirror of
https://gitee.com/ant-design-blazor/ant-design-blazor.git
synced 2024-12-01 19:48:17 +08:00
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:
parent
ab939b927f
commit
21a076dff5
67
components/core/Helpers/JsonElementHelper.cs
Normal file
67
components/core/Helpers/JsonElementHelper.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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; }
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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.
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user