Blazor MudBlazor多级子组件表单验证不触发问题排查
问题描述
使用Blazor MudBlazor v6.17.0,现有两级组件结构:
- 基础组件
CustomerComponent,包含MudAutocomplete用于选择客户名称 - 容器组件
CustomerTemplateComponent,包含EditForm并引用CustomerComponent
点击保存按钮时,表单未执行验证,API收到无效模型数据,且底层CustomerComponent的绑定未正常生效;但将CustomerComponent直接用于顶层表单时,验证功能正常。询问是否需要使用级联参数或存在其他问题。
相关代码
CustomerComponent
<div class="row" style="padding-top:10px;"> <div class="col-4 mb-3"> <MudAutocomplete id="name" For="@(() => Customer.Name)" T="string" Label="Name:" @bind-Value="Customer.Name" SearchFunc="@SearchCustomer" Margin="Margin.Dense" Dense="true" Variant="Variant.Outlined" /> </div> </div> @code { [Parameter] public Customer Customer { get; set; } [Parameter] public IEnumerable<string> CustomerList { get; set; } private Task<IEnumerable<string>> SearchCustomer(string value) { if (string.IsNullOrEmpty(value)) { Customer.Name = ""; return Task.FromResult(CustomerList); } var filteredList = CustomerList.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); return Task.FromResult(filteredList); } }
CustomerTemplateComponent
<EditForm Model="@Template" OnValidSubmit="@SaveEvent"> <DataAnnotationsValidator/> <br /> <div class="row" style="padding-top: 6px;"> <div class="col-12"> <MudTextField id="TemplateName" For="@(() => Template.TemplateName)" @bind-Value="@Template.TemplateName" Label="Template Name:" Variant="Variant.Outlined" Margin="Margin.Dense"></MudTextField> </div> </div> <CustomerComponent CustomerList="@CustomerList" Customer="@Template.Customer" /> <div class="row" style="padding-top:8px;"> <div class="col-12 text-end mb-3"> <button class="btn btn-primary" disabled="@Processing" id="Save-Button">Save</button> <div type="button" class="btn btn-secondary" @onclick="@CancelEvent" id="Cancel-Button">Cancel</div> </div> </div> </EditForm> @code { [Parameter] public bool Processing { get; set; } [Parameter] public Template Template { get; set; } [Parameter] public EventCallback CancelEvent { get; set; } [Parameter] public EventCallback SaveEvent { get; set; } [Parameter] public IEnumerable<string> CustomerList { get; set; } }
顶层引用代码
<MudPaper Elevation="10"> <MudGrid Class="d-flex align-content-center justify-center flex-grow-1 gap-4" Style="padding:10px;"> <CustomerTemplateComponent CancelEvent="@Cancel" CustomerList="@Customers" SaveEvent="@Save" Processing="@Processing" Template="@_template" /> </MudGrid> </MudPaper> @code { private async Task Save() { Processing = true; try { await _templateService.SaveAsync(_template); ToastService.ShowSuccess("Template Updated."); NavigationManager.NavigateTo("/tradetemplates"); } catch (Exception ex) { Logger.Error(ex, "Error saving templates."); ToastService.ShowError(ex.Message); } finally { Processing = false; } } }
实体类定义
public class Template { public string TemplateName { get; set; } public Customer Customer { get; set; } } public class Customer { public string Name { get; set; } }
解决方案
问题出在三个核心点:缺少验证规则定义、子组件输入控件未关联顶层表单验证上下文、保存按钮未明确触发表单提交流程,具体修复步骤如下:
1. 为实体类添加数据验证注解
验证需要基于明确规则触发,为实体类添加DataAnnotations验证特性:
using System.ComponentModel.DataAnnotations; public class Template { [Required(ErrorMessage = "模板名称不能为空")] public string TemplateName { get; set; } [Required(ErrorMessage = "请选择客户")] public Customer Customer { get; set; } } public class Customer { [Required(ErrorMessage = "客户名称不能为空")] public string Name { get; set; } }
2. 修正子组件验证关联问题
子组件CustomerComponent中的MudAutocomplete的For表达式指向自身参数,而非顶层Template模型的属性,导致验证上下文无法识别该字段。
修改CustomerComponent,新增表达式参数接收顶层模型的字段路径:
<div class="row" style="padding-top:10px;"> <div class="col-4 mb-3"> <MudAutocomplete id="name" For="@CustomerNameExpression" T="string" Label="Name:" @bind-Value="Customer.Name" SearchFunc="@SearchCustomer" Margin="Margin.Dense" Dense="true" Variant="Variant.Outlined" /> </div> </div> @code { [Parameter] public Customer Customer { get; set; } [Parameter] public IEnumerable<string> CustomerList { get; set; } [Parameter] public Expression<Func<string>> CustomerNameExpression { get; set; } private Task<IEnumerable<string>> SearchCustomer(string value) { if (string.IsNullOrEmpty(value)) { Customer.Name = ""; return Task.FromResult(CustomerList); } var filteredList = CustomerList.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase)); return Task.FromResult(filteredList); } }
在CustomerTemplateComponent引用CustomerComponent时,传入顶层模型的表达式:
<CustomerComponent CustomerList="@CustomerList" Customer="@Template.Customer" CustomerNameExpression="@(() => Template.Customer.Name)" />
3. 明确设置保存按钮的提交类型
确保保存按钮触发EditForm的提交流程,为按钮添加type="submit"属性:
<button type="submit" class="btn btn-primary" disabled="@Processing" id="Save-Button">Save</button>
内容的提问来源于stack exchange,提问作者BankMan101
相关产品推荐
相关产品推荐

