Skip to content

Commit 1a30a62

Browse files
feat(table): fixed column not allow drag (#8059)
* feat(table):当表格存在固定列时,只允许相同属性列之间相互交换列顺序 feat(table):当表格存在固定列时,只允许相同属性列之间相互交换列顺序 * feat(table):当表格存在固定列时,只允许相同属性列之间相互交换列顺序 revert: 将数据列Fixed属性为true时,Column的Width默认宽度设置为200,保持与组件中DefaultFixedColumnWidth属性一致 * Revert "feat(table):当表格存在固定列时,只允许相同属性列之间相互交换列顺序" This reverts commit a739ed4. * Revert "feat(table):当表格存在固定列时,只允许相同属性列之间相互交换列顺序" This reverts commit 1990968. * refactor: 固定列不允许拖动 * feat: 只允许拖动非固定列 * test: 增加单元测试 * doc: 更新示例 * doc: 更新说明文档 --------- Co-authored-by: Argo Zhang <argo@live.ca>
1 parent db208d3 commit 1a30a62

6 files changed

Lines changed: 100 additions & 17 deletions

File tree

‎src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnDrag.razor‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
<h4>@Localizer["TablesColumnDescription"]</h4>
1010

11-
1211
<DemoBlock Title="@Localizer["AllowDragOrderTitle"]" Introduction="@Localizer["AllowDragOrderIntro"]" Name="AllowDragColumn">
1312
<section ignore>
1413
<p>@((MarkupString)Localizer["AllowDragOrderDesc"].Value)</p>
@@ -22,10 +21,12 @@
2221
IsMultipleSelect="true" ShowExtendButtons="false"
2322
OnQueryAsync="@OnQueryAsync">
2423
<TableColumns>
25-
<TableColumn @bind-Field="@context.DateTime" Width="120" FormatString="yyyy-MM-dd" />
26-
<TableColumn @bind-Field="@context.Name" Width="100" />
24+
<TableColumn @bind-Field="@context.DateTime" Width="120" FormatString="yyyy-MM-dd" Fixed="true" />
25+
<TableColumn @bind-Field="@context.Name" Width="100" Fixed="true" />
2726
<TableColumn @bind-Field="@context.Address" />
28-
<TableColumn @bind-Field="@context.Count" />
27+
<TableColumn @bind-Field="@context.Complete" />
28+
<TableColumn @bind-Field="@context.Education" />
29+
<TableColumn @bind-Field="@context.Count" Fixed="true" />
2930
</TableColumns>
3031
<TableToolbarTemplate>
3132
<TableToolbarButton Text="@Localizer["ResetButtonText"]" OnClickWithoutRender="Reset"></TableToolbarButton>

‎src/BootstrapBlazor.Server/Locales/en-US.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4639,7 +4639,7 @@
46394639
},
46404640
"BootstrapBlazor.Server.Components.Samples.Table.TablesColumnDrag": {
46414641
"AllowDragOrderDesc": "<p>Pressing the mouse over a column heading and dragging it to another column heading position can adjust the column to be in front of the target column, but the built-in columns in the <code>Table</code> component, such as detail row, row number, selection, and operation columns, cannot be adjusted</p><p>This example enables local storage by setting the <code>ClientTableName</code> parameter. After dragging and adjusting the order, the page can be refreshed, and the column order remains in the previous state</p><p>After version <code>10.6.1</code>, use <code>OnTableColumnClientStatusChanged</code> to uniformly handle column dragging, column resizing, and auto-fit column width callbacks, replacing the original <code>OnDragColumnEndAsync</code>, <code>OnResizeColumnAsync</code>, and <code>OnAutoFitContentAsync</code> callbacks.</p><p><b>Notes:</b></p><p>Table state persistence has two modes. If the <code>ClientTableName</code> property is set, browser local storage is used to persist information. If it is not set, server-side storage persistence is implemented through callbacks. The persistence structure is <code>TableColumnClientStatus</code>, which consists of the column state collection and the table width parameter.</p><p>The table width parameter defaults to 0. When all columns have width values, the table width parameter is the actual width rendered on the client. A value of 0 means the table width is adaptive.</p><p>When using browser local storage for persistence, no additional settings are required. The table automatically loads the client state.</p><p>When using server-side storage for persistence, handle table state loading and saving logic in callbacks. In actual use, the state can be stored in a database or other storage as needed. Use the <code>OnTableColumnClientStatusChanged</code> callback to handle server-side state changes, and use the <code>OnLoadTableColumnClientStatus</code> callback to restore the table persistence state.</p>",
4642-
"AllowDragOrderIntro": "By specifying <code>AllowDragColumn</code>, set the table columns to allow dragging column headings to adjust the table column order",
4642+
"AllowDragOrderIntro": "By specifying <code>AllowDragColumn</code>, set the table columns to allow dragging column headings to adjust the table column order; The current design only supports dragging non-fixed columns.",
46434643
"AllowDragOrderTitle": "Allow dragging column headings to adjust table column order",
46444644
"ClearTableColumnClientStatusDesc": "By calling the <code>ClearTableColumnClientStatus</code> method of the table component instance, the current persistent settings are cleared, restoring the table to its default settings.",
46454645
"ResetButtonText": "Reset",

‎src/BootstrapBlazor.Server/Locales/zh-CN.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4639,7 +4639,7 @@
46394639
},
46404640
"BootstrapBlazor.Server.Components.Samples.Table.TablesColumnDrag": {
46414641
"AllowDragOrderDesc": "<p>在列标题上按下鼠标拖动到其他列标题位置可将该列调整至目标列之前,但 <code>Table</code> 组件内置的列如明细行列、行号列、选择列、操作列等不可被调整</p><p>本示例通过设置 <code>ClientTableName</code> 参数开启了本地化存储,拖动调整顺序后,可刷新页面,列顺序是保持上次状态的</p><p><code>10.6.1</code> 版本后使用 <code>OnTableColumnClientStatusChanged</code> 统一处理列拖拽、列宽调整与自适应列宽回调,移除原 <code>OnDragColumnEndAsync</code> <code>OnResizeColumnAsync</code> 和 <code>OnAutoFitContentAsync</code> 回调。</p><p><b>注意事项:</b></p><p>表格状态持久化功能分两种情况,设置 <code>ClientTableName</code> 属性即使用浏览器本地存储持久化信息,如果未设置则通过回调使用服务器端存储持久化信息。持久化信息结构体为 <code>TableColumnClientStatus</code> 由列状态集合以及表格宽度参数组成。</p><p>表格宽度参数默认为 0 当所有列宽度均有值时,表格宽度参数值为表格在客户端渲染的实际宽度;为 0 表示表格宽度自适应</p><p>使用浏览器本地存储持久化信息时,无需任何设置,表格会自动加载客户端状态</p><p>使用服务器端存储持久化信息时,需在回调中处理表格状态加载与保存逻辑,实际使用中可根据需要使用数据库或其他方式进行存储;通过 <code>OnTableColumnClientStatusChanged</code> 回调处理服务器端状态,通过 <code>OnLoadTableColumnClientStatus</code> 回调方法对表格进行持久化状态恢复操作</p>",
4642-
"AllowDragOrderIntro": "通过指定 <code>AllowDragColumn</code> 设置表格列允许拖动列标题调整表格列顺序",
4642+
"AllowDragOrderIntro": "通过指定 <code>AllowDragColumn</code> 设置表格列允许拖动列标题调整表格列顺序;目前设计上仅支持非固定列拖动",
46434643
"AllowDragOrderTitle": "允许拖动列标题调整表格列顺序",
46444644
"ClearTableColumnClientStatusDesc": "通过调用表格组件实例方法 <code>ClearTableColumnClientStatus</code> 清除当前持久化设置恢复表格为默认设置",
46454645
"ResetButtonText": "重置",

‎src/BootstrapBlazor/Components/Table/Table.razor‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@
310310
style="@GetFixedCellStyleString(col, ActualScrollWidth)"
311311
data-bb-field="@fieldName"
312312
TriggerClick="col.GetSortable()" OnClick="@OnClickHeader(col)"
313-
draggable="@DraggableString">
313+
draggable="@GetDraggableString(col)">
314314
<div class="@GetHeaderWrapperClassString(col)">
315315
@if (col.GetShowCopyColumn())
316316
{

‎src/BootstrapBlazor/Components/Table/Table.razor.cs‎

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1870,7 +1870,7 @@ private async Task OnContextMenu(MouseEventArgs e, TItem item)
18701870
[Parameter]
18711871
public bool AllowDragColumn { get; set; }
18721872

1873-
private string? DraggableString => AllowDragColumn ? "true" : null;
1873+
private string? GetDraggableString(ITableColumn col) => AllowDragColumn && !col.Fixed ? "true" : null;
18741874

18751875
/// <summary>
18761876
/// <para lang="zh">获得/设置 拖动列结束回调方法,默认 null 可存储数据库用于服务器端保持列顺序</para>
@@ -1959,27 +1959,40 @@ public async Task ClearTableColumnClientStatus()
19591959
[JSInvokable]
19601960
public async Task DragColumnCallback(int originIndex, int currentIndex)
19611961
{
1962+
if (!AllowDragColumn || originIndex == currentIndex)
1963+
{
1964+
return;
1965+
}
1966+
1967+
var draggableColumnNames = GetVisibleColumns().Where(i => !i.Fixed).Select(i => i.GetFieldName()).ToList();
1968+
var sourceName = draggableColumnNames.ElementAtOrDefault(originIndex);
1969+
var targetName = draggableColumnNames.ElementAtOrDefault(currentIndex);
1970+
if (string.IsNullOrEmpty(sourceName) || string.IsNullOrEmpty(targetName))
1971+
{
1972+
return;
1973+
}
1974+
19621975
// 更新缓存数据中列顺序
1963-
var visibleColumns = _tableColumnStates.Where(i => i.Visible);
1964-
var firstColumn = visibleColumns.ElementAtOrDefault(originIndex);
1976+
var firstColumn = _tableColumnStates.Find(i => i.Name == sourceName);
19651977
if (firstColumn != null)
19661978
{
1967-
var targetColumn = visibleColumns.ElementAtOrDefault(currentIndex);
1968-
if (targetColumn != null)
1979+
var targetState = _tableColumnStates.Find(i => i.Name == targetName);
1980+
if (targetState != null)
19691981
{
19701982
_tableColumnStates.Remove(firstColumn);
1971-
var pos = _tableColumnStates.IndexOf(targetColumn);
1983+
var pos = _tableColumnStates.IndexOf(targetState);
19721984
_tableColumnStates.Insert(pos, firstColumn);
19731985

19741986
if (OnTableColumnClientStatusChanged != null)
19751987
{
19761988
await OnTableColumnClientStatusChanged(firstColumn.Name, _tableColumnStateCache);
19771989
}
1978-
}
1979-
_resetColumns = true;
1980-
_invoke = true;
19811990

1982-
StateHasChanged();
1991+
_resetColumns = true;
1992+
_invoke = true;
1993+
1994+
StateHasChanged();
1995+
}
19831996
}
19841997
}
19851998

‎test/UnitTest/Components/TableTest.cs‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8870,6 +8870,75 @@ await cut.InvokeAsync(async () =>
88708870
});
88718871
}
88728872

8873+
[Fact]
8874+
public async Task AllowDragColumn_FixedColumn_Ok()
8875+
{
8876+
string? name = null;
8877+
var localizer = Context.Services.GetRequiredService<IStringLocalizer<Foo>>();
8878+
var cut = Context.Render<BootstrapBlazorRoot>(pb =>
8879+
{
8880+
pb.AddChildContent<Table<Foo>>(pb =>
8881+
{
8882+
pb.Add(a => a.RenderMode, TableRenderMode.Table);
8883+
pb.Add(a => a.AllowDragColumn, true);
8884+
pb.Add(a => a.Items, Foo.GenerateFoo(localizer, 2));
8885+
pb.Add(a => a.OnTableColumnClientStatusChanged, (fieldName, state) =>
8886+
{
8887+
name = fieldName;
8888+
return Task.CompletedTask;
8889+
});
8890+
pb.Add(a => a.TableColumns, foo => builder =>
8891+
{
8892+
builder.OpenComponent<TableColumn<Foo, string>>(0);
8893+
builder.AddAttribute(1, nameof(TableColumn<Foo, string>.Field), foo.Name);
8894+
builder.AddAttribute(2, nameof(TableColumn<Foo, string>.FieldExpression), Utility.GenerateValueExpression(foo, nameof(Foo.Name), typeof(string)));
8895+
builder.AddAttribute(3, nameof(TableColumn<Foo, string>.Fixed), true);
8896+
builder.CloseComponent();
8897+
8898+
builder.OpenComponent<TableColumn<Foo, string>>(4);
8899+
builder.AddAttribute(5, nameof(TableColumn<Foo, string>.Field), foo.Address);
8900+
builder.AddAttribute(6, nameof(TableColumn<Foo, string>.FieldExpression), Utility.GenerateValueExpression(foo, nameof(Foo.Address), typeof(string)));
8901+
builder.CloseComponent();
8902+
8903+
builder.OpenComponent<TableColumn<Foo, int>>(7);
8904+
builder.AddAttribute(8, nameof(TableColumn<Foo, int>.Field), foo.Count);
8905+
builder.AddAttribute(9, nameof(TableColumn<Foo, int>.FieldExpression), Utility.GenerateValueExpression(foo, nameof(Foo.Count), typeof(int)));
8906+
builder.CloseComponent();
8907+
});
8908+
});
8909+
});
8910+
8911+
var table = cut.FindComponent<Table<Foo>>();
8912+
var columns = cut.FindAll("th");
8913+
Assert.False(columns[0].HasAttribute("draggable"));
8914+
Assert.Equal("true", columns[1].GetAttribute("draggable"));
8915+
Assert.Equal("true", columns[2].GetAttribute("draggable"));
8916+
8917+
await cut.InvokeAsync(() => table.Instance.DragColumnCallback(1, 0));
8918+
Assert.Equal(nameof(Foo.Count), name);
8919+
columns = cut.FindAll("th");
8920+
Assert.Equal(nameof(Foo.Name), columns[0].GetAttribute("data-bb-field"));
8921+
Assert.Equal(nameof(Foo.Count), columns[1].GetAttribute("data-bb-field"));
8922+
Assert.Equal(nameof(Foo.Address), columns[2].GetAttribute("data-bb-field"));
8923+
8924+
await cut.InvokeAsync(() => table.Instance.DragColumnCallback(1, 0));
8925+
Assert.Equal(nameof(Foo.Address), name);
8926+
columns = cut.FindAll("th");
8927+
Assert.Equal(nameof(Foo.Name), columns[0].GetAttribute("data-bb-field"));
8928+
Assert.Equal(nameof(Foo.Address), columns[1].GetAttribute("data-bb-field"));
8929+
Assert.Equal(nameof(Foo.Count), columns[2].GetAttribute("data-bb-field"));
8930+
8931+
// 测试相同列拖动
8932+
await cut.InvokeAsync(() => table.Instance.DragColumnCallback(0, 0));
8933+
8934+
// 更改为不允许拖动
8935+
table.Render(pb =>
8936+
{
8937+
pb.Add(a => a.AllowDragColumn, false);
8938+
});
8939+
await cut.InvokeAsync(() => table.Instance.DragColumnCallback(1, 0));
8940+
}
8941+
88738942
[Fact]
88748943
public async Task OnTableColumnClientStatusChanged_ResizeColumn_Ok()
88758944
{

0 commit comments

Comments
 (0)