Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 6 additions & 13 deletions src/BootstrapBlazor/Components/Table/Table.razor
Original file line number Diff line number Diff line change
Expand Up @@ -787,19 +787,7 @@
{
@RenderRowExtendButtons(item)
}
@if (RowContentTemplate != null)
{
var columns = GetVisibleColumns();
@RowContentTemplate(new(item, columns, ActiveRenderMode))
}
else
{
@RenderContentRow(item)
}
@if (ShowExtendButtons && !IsExtendButtonsInRowHeader)
{
@RenderRowExtendButtons(item)
}
@RenderRowCell(item)
</DynamicElement>;

RenderFragment<TableContentCellContext<TItem>> RenderContentCell => context =>
Expand Down Expand Up @@ -1152,4 +1140,9 @@
OnValueChanged="visible => OnToggleColumnVisible(item.Name, visible)">
</Checkbox>
</div>;

RenderFragment<TItem> RenderRowContentWithValidateForm => item =>
@<ValidateForm @ref="_inCellValidateForm" Model="EditModel" IsFormless="true" ShowLabel="false">
@RenderRowContent(item)
</ValidateForm>;
}
6 changes: 6 additions & 0 deletions src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,12 @@ private async Task ClickEditButton(TItem item)

private async Task ClickUpdateButtonCallback()
{
// 验证 InCell 模式下的表单
if (!_inCellValidateForm.Validate())
{
return;
}

var context = new EditContext(EditModel);
await SaveAsync(context, AddInCell ? ItemChangedType.Add : ItemChangedType.Update);
}
Expand Down
5 changes: 5 additions & 0 deletions src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,11 @@ private bool GetColumnsListState(ColumnVisibleItem item)

private bool InCellMode => AddInCell || EditInCell;

/// <summary>
/// 获得 InCell 模式下的 ValidateForm 实例
/// </summary>
private ValidateForm _inCellValidateForm = default!;

/// <summary>
/// 新建按钮方法
/// </summary>
Expand Down
32 changes: 31 additions & 1 deletion src/BootstrapBlazor/Components/Table/Table.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1501,7 +1501,7 @@ RenderFragment RenderTemplate() => col.Template == null
: col.Template(item);

RenderFragment RenderEditTemplate() => col.EditTemplate == null
? new RenderFragment(builder => builder.CreateComponentByFieldType(this, col, item, changedType, isSearch: false, col.GetLookupService(InjectLookupService), skipValidate: true))
? new RenderFragment(builder => builder.CreateComponentByFieldType(this, col, item, changedType, isSearch: false, col.GetLookupService(InjectLookupService), skipValidate: false))
: col.EditTemplate(item);
}

Expand Down Expand Up @@ -1840,6 +1840,36 @@ private void OnTouchEnd()

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

private RenderFragment RenderRowCell(TItem item) => builder =>
{
var isInCellEditRow = InCellMode && SelectedRows.FirstOrDefault() == item;
if (isInCellEditRow)
{
builder.AddContent(0, RenderRowContentWithValidateForm(item));
}
else
{
builder.AddContent(1, RenderRowContent(item));
}
};

private RenderFragment RenderRowContent(TItem item) => builder =>
{
if (RowContentTemplate != null)
{
var columns = GetVisibleColumns();
builder.AddContent(0, RowContentTemplate(new(item, columns, ActiveRenderMode)));
}
else
{
builder.AddContent(1, RenderContentRow(item));
}
if (ShowExtendButtons && !IsExtendButtonsInRowHeader)
{
builder.AddContent(2, RenderRowExtendButtons(item));
}
};

/// <summary>
/// Dispose 方法
/// </summary>
Expand Down
26 changes: 18 additions & 8 deletions src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
@namespace BootstrapBlazor.Components
@namespace BootstrapBlazor.Components
@inherits BootstrapModuleComponentBase
@attribute [BootstrapModuleAutoLoader]

@if (Model != null)
{
<CascadingValue Value="this" IsFixed="true">
<EditForm @attributes="@AdditionalAttributes" id="@Id" Model="@Model"
data-bb-dissubmit="@DisableAutoSubmitString" data-bb-invalid-result="@ShowAllInvalidResultString"
style="@StyleString"
OnValidSubmit="@OnValidSubmitForm" OnInvalidSubmit="@OnInvalidSubmitForm">
<BootstrapBlazorDataAnnotationsValidator @ref="Validator" />
@ChildContent
</EditForm>
@if (IsFormless)
{
<CascadingValue Value="_formlessEditContext" IsFixed="true">
<BootstrapBlazorDataAnnotationsValidator @ref="Validator" />
@ChildContent
</CascadingValue>
}
else
{
<EditForm @attributes="@AdditionalAttributes" id="@Id" Model="@Model"
data-bb-dissubmit="@DisableAutoSubmitString" data-bb-invalid-result="@ShowAllInvalidResultString"
style="@StyleString"
OnValidSubmit="@OnValidSubmitForm" OnInvalidSubmit="@OnInvalidSubmitForm">
<BootstrapBlazorDataAnnotationsValidator @ref="Validator" />
@ChildContent
</EditForm>
}
</CascadingValue>
}
25 changes: 25 additions & 0 deletions src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ public partial class ValidateForm
[Parameter]
public bool? ShowLabelTooltip { get; set; }

/// <summary>
/// 获得/设置 是否为无表单模式 默认 false
/// </summary>
/// <remarks>设置为 true 时不渲染 form 元素,仅级联 EditContext 用于 Table InCell 编辑模式</remarks>
[Parameter]
public bool IsFormless { get; set; }

/// <summary>
/// 获得/设置 是否禁用表单内回车自动提交功能 默认 null 未设置
/// </summary>
Expand Down Expand Up @@ -146,6 +153,12 @@ protected override void OnParametersSet()
{
DisableAutoSubmitFormByEnter = BootstrapBlazorOptions.CurrentValue.DisableAutoSubmitFormByEnter.Value;
}

// 无表单模式下创建/更新 EditContext
if (IsFormless)
{
_formlessEditContext ??= new EditContext(Model);
}
}

/// <summary>
Expand Down Expand Up @@ -330,6 +343,13 @@ internal async Task ValidateObject(ValidationContext context, List<ValidationRes
{
await validator.ToggleMessage(messages);
}

// 确保 _invalid 在没有验证组件时被正确设置
// Ensure _invalid is properly set when there are no validation components
if (_validatorCache.IsEmpty)
{
_invalid = results.Count > 0;
}
}
}

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

/// <summary>
/// 获得/设置 无表单模式下的 EditContext 实例
/// </summary>
private EditContext? _formlessEditContext;

/// <summary>
/// 验证方法 用于代码调用触发表单验证
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions test/UnitTest/Components/TableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3887,6 +3887,19 @@ public async Task InCell_Ok()
});
var button = cut.Find("tbody tr td button");
await cut.InvokeAsync(() => button.Click());

// 增加 Validate 测试
// 设置姓名为 null 保存按钮不成功
var nameField = cut.Find("tbody tr td input");
Assert.Equal("张三 0001", nameField.GetAttribute("value"));

await cut.InvokeAsync(() => nameField.Change(""));
Assert.Contains("is-invalid", nameField.ToMarkup());
await cut.InvokeAsync(() => button.Click());

await cut.InvokeAsync(() => nameField.Change("张三 0001"));
Assert.Contains("is-valid", nameField.ToMarkup());
await cut.InvokeAsync(() => button.Click());
}

[Fact]
Expand Down