Skip to content

Commit 1f60cea

Browse files
celadarisArgoZhang
andcommitted
feat(Table): support validate InCell Mode (#7437)
* refactor: 代码重构精简代码逻辑 * refactor: 精简代码 * refactor: 优化性能 * refactor: 消除提示信息 * test: 增加单元测试 * refactor: 更新单元测试 --------- Co-authored-by: Argo Zhang <[email protected]>
1 parent 814a8c4 commit 1f60cea

File tree

7 files changed

+104
-22
lines changed

7 files changed

+104
-22
lines changed

src/BootstrapBlazor/Components/Table/Table.razor

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -787,19 +787,7 @@
787787
{
788788
@RenderRowExtendButtons(item)
789789
}
790-
@if (RowContentTemplate != null)
791-
{
792-
var columns = GetVisibleColumns();
793-
@RowContentTemplate(new(item, columns, ActiveRenderMode))
794-
}
795-
else
796-
{
797-
@RenderContentRow(item)
798-
}
799-
@if (ShowExtendButtons && !IsExtendButtonsInRowHeader)
800-
{
801-
@RenderRowExtendButtons(item)
802-
}
790+
@RenderRowCell(item)
803791
</DynamicElement>;
804792

805793
RenderFragment<TableContentCellContext<TItem>> RenderContentCell => context =>
@@ -1152,4 +1140,9 @@
11521140
OnValueChanged="visible => OnToggleColumnVisible(item.Name, visible)">
11531141
</Checkbox>
11541142
</div>;
1143+
1144+
RenderFragment<TItem> RenderRowContentWithValidateForm => item =>
1145+
@<ValidateForm @ref="_inCellValidateForm" Model="EditModel" IsFormless="true" ShowLabel="false">
1146+
@RenderRowContent(item)
1147+
</ValidateForm>;
11551148
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,12 @@ private async Task ClickEditButton(TItem item)
703703

704704
private async Task ClickUpdateButtonCallback()
705705
{
706+
// 验证 InCell 模式下的表单
707+
if (!_inCellValidateForm.Validate())
708+
{
709+
return;
710+
}
711+
706712
var context = new EditContext(EditModel);
707713
await SaveAsync(context, AddInCell ? ItemChangedType.Add : ItemChangedType.Update);
708714
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,11 @@ private bool GetColumnsListState(ColumnVisibleItem item)
499499

500500
private bool InCellMode => AddInCell || EditInCell;
501501

502+
/// <summary>
503+
/// 获得 InCell 模式下的 ValidateForm 实例
504+
/// </summary>
505+
private ValidateForm _inCellValidateForm = default!;
506+
502507
/// <summary>
503508
/// 新建按钮方法
504509
/// </summary>

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,7 @@ RenderFragment RenderTemplate() => col.Template == null
15011501
: col.Template(item);
15021502

15031503
RenderFragment RenderEditTemplate() => col.EditTemplate == null
1504-
? new RenderFragment(builder => builder.CreateComponentByFieldType(this, col, item, changedType, isSearch: false, col.GetLookupService(InjectLookupService), skipValidate: true))
1504+
? new RenderFragment(builder => builder.CreateComponentByFieldType(this, col, item, changedType, isSearch: false, col.GetLookupService(InjectLookupService), skipValidate: false))
15051505
: col.EditTemplate(item);
15061506
}
15071507

@@ -1840,6 +1840,36 @@ private void OnTouchEnd()
18401840

18411841
private object? GetKeyByITem(TItem item) => SortableList != null ? item : null; //OnGetRowKey?.Invoke(item);
18421842

1843+
private RenderFragment RenderRowCell(TItem item) => builder =>
1844+
{
1845+
var isInCellEditRow = InCellMode && SelectedRows.FirstOrDefault() == item;
1846+
if (isInCellEditRow)
1847+
{
1848+
builder.AddContent(0, RenderRowContentWithValidateForm(item));
1849+
}
1850+
else
1851+
{
1852+
builder.AddContent(1, RenderRowContent(item));
1853+
}
1854+
};
1855+
1856+
private RenderFragment RenderRowContent(TItem item) => builder =>
1857+
{
1858+
if (RowContentTemplate != null)
1859+
{
1860+
var columns = GetVisibleColumns();
1861+
builder.AddContent(0, RowContentTemplate(new(item, columns, ActiveRenderMode)));
1862+
}
1863+
else
1864+
{
1865+
builder.AddContent(1, RenderContentRow(item));
1866+
}
1867+
if (ShowExtendButtons && !IsExtendButtonsInRowHeader)
1868+
{
1869+
builder.AddContent(2, RenderRowExtendButtons(item));
1870+
}
1871+
};
1872+
18431873
/// <summary>
18441874
/// Dispose 方法
18451875
/// </summary>
Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
1-
@namespace BootstrapBlazor.Components
1+
@namespace BootstrapBlazor.Components
22
@inherits BootstrapModuleComponentBase
33
@attribute [BootstrapModuleAutoLoader]
44

55
@if (Model != null)
66
{
77
<CascadingValue Value="this" IsFixed="true">
8-
<EditForm @attributes="@AdditionalAttributes" id="@Id" Model="@Model"
9-
data-bb-dissubmit="@DisableAutoSubmitString" data-bb-invalid-result="@ShowAllInvalidResultString"
10-
style="@StyleString"
11-
OnValidSubmit="@OnValidSubmitForm" OnInvalidSubmit="@OnInvalidSubmitForm">
12-
<BootstrapBlazorDataAnnotationsValidator @ref="Validator" />
13-
@ChildContent
14-
</EditForm>
8+
@if (IsFormless)
9+
{
10+
<CascadingValue Value="_formlessEditContext" IsFixed="true">
11+
<BootstrapBlazorDataAnnotationsValidator @ref="Validator" />
12+
@ChildContent
13+
</CascadingValue>
14+
}
15+
else
16+
{
17+
<EditForm @attributes="@AdditionalAttributes" id="@Id" Model="@Model"
18+
data-bb-dissubmit="@DisableAutoSubmitString" data-bb-invalid-result="@ShowAllInvalidResultString"
19+
style="@StyleString"
20+
OnValidSubmit="@OnValidSubmitForm" OnInvalidSubmit="@OnInvalidSubmitForm">
21+
<BootstrapBlazorDataAnnotationsValidator @ref="Validator" />
22+
@ChildContent
23+
</EditForm>
24+
}
1525
</CascadingValue>
1626
}

src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ public partial class ValidateForm
8383
[Parameter]
8484
public bool? ShowLabelTooltip { get; set; }
8585

86+
/// <summary>
87+
/// 获得/设置 是否为无表单模式 默认 false
88+
/// </summary>
89+
/// <remarks>设置为 true 时不渲染 form 元素,仅级联 EditContext 用于 Table InCell 编辑模式</remarks>
90+
[Parameter]
91+
public bool IsFormless { get; set; }
92+
8693
/// <summary>
8794
/// 获得/设置 是否禁用表单内回车自动提交功能 默认 null 未设置
8895
/// </summary>
@@ -146,6 +153,12 @@ protected override void OnParametersSet()
146153
{
147154
DisableAutoSubmitFormByEnter = BootstrapBlazorOptions.CurrentValue.DisableAutoSubmitFormByEnter.Value;
148155
}
156+
157+
// 无表单模式下创建/更新 EditContext
158+
if (IsFormless)
159+
{
160+
_formlessEditContext ??= new EditContext(Model);
161+
}
149162
}
150163

151164
/// <summary>
@@ -330,6 +343,13 @@ internal async Task ValidateObject(ValidationContext context, List<ValidationRes
330343
{
331344
await validator.ToggleMessage(messages);
332345
}
346+
347+
// 确保 _invalid 在没有验证组件时被正确设置
348+
// Ensure _invalid is properly set when there are no validation components
349+
if (_validatorCache.IsEmpty)
350+
{
351+
_invalid = results.Count > 0;
352+
}
333353
}
334354
}
335355

@@ -636,6 +656,11 @@ private async Task OnInvalidSubmitForm(EditContext context)
636656
[NotNull]
637657
private BootstrapBlazorDataAnnotationsValidator? Validator { get; set; }
638658

659+
/// <summary>
660+
/// 获得/设置 无表单模式下的 EditContext 实例
661+
/// </summary>
662+
private EditContext? _formlessEditContext;
663+
639664
/// <summary>
640665
/// 验证方法 用于代码调用触发表单验证
641666
/// </summary>

test/UnitTest/Components/TableTest.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3887,6 +3887,19 @@ public async Task InCell_Ok()
38873887
});
38883888
var button = cut.Find("tbody tr td button");
38893889
await cut.InvokeAsync(() => button.Click());
3890+
3891+
// 增加 Validate 测试
3892+
// 设置姓名为 null 保存按钮不成功
3893+
var nameField = cut.Find("tbody tr td input");
3894+
Assert.Equal("张三 0001", nameField.GetAttribute("value"));
3895+
3896+
await cut.InvokeAsync(() => nameField.Change(""));
3897+
Assert.Contains("is-invalid", nameField.ToMarkup());
3898+
await cut.InvokeAsync(() => button.Click());
3899+
3900+
await cut.InvokeAsync(() => nameField.Change("张三 0001"));
3901+
Assert.Contains("is-valid", nameField.ToMarkup());
3902+
await cut.InvokeAsync(() => button.Click());
38903903
}
38913904

38923905
[Fact]

0 commit comments

Comments
 (0)