根据本文,我正在使用向导组件逻辑创建一个多步骤 Blazor 表单。项目是 .NET 5.0 Blazor 客户端(托管)。有一个Wizard
具有WizardStep
子组件的父组件。
我正在尝试创建一个简单的两步表单。步号 1 包含一个输入日期控件和步骤号。2/最后一步包含一个文本区域控件。
从上图中可以看出,我的表单第 1 步中的下一步按钮有一个类型“按钮”。单击此Next按钮时,将替换当前组件并呈现WizardStep
下一个/最终组件。WizardStep
这个 finalWizardStep
包含文本区域控件,并且Next按钮被Submit按钮替换。但是,可以看出最后一步显示了Validation错误。无需在最后一步中单击提交按钮即可出现这些验证错误。
我已经调试了应用程序,并且可以看出在步骤 1 中单击“下一步”按钮后,表单会尝试提交,这就是出现验证错误的原因。这不应该发生,因为下一步按钮的类型是“按钮”。
为什么会出现这个问题?表单只能在单击“提交”类型的按钮后提交,该按钮出现在向导的最后一步。
上图中要注意的另一件事是,表单的下一步/最后一步中的提交按钮看起来好像被单击了一样。为什么?
形式
<EditForm Model="model" OnValidSubmit="SubmitValidForm">
<DataAnnotationsValidator />
<ValidationSummary />
<Wizard Id="TestForm">
<WizardStep Name="First Step">
<div class="form-group">
<label>Date:</label>
<div>
<InputDate @bind-Value="@model.Date" class="form-control" />
</div>
<ValidationMessage For="@(() => model.Date)" />
</div>
</WizardStep>
<WizardStep Name="Final Step">
<div class="form-group ">
<label>Details:</label>
<div>
<InputTextArea @bind-Value="@model.Entry" class="form-control" rows="8" />
</div>
<ValidationMessage For="@(() => model.Entry)" />
</div>
</WizardStep>
</Wizard>
</EditForm>
向导
<CascadingValue Value="this">
<div id="@Id">
<div class="card">
<div class="card-header">
<div class="row justify-content-center align-items-center">
Step @(ActiveStepIx + 1) of @Steps.Count
</div>
</div>
<div class="card-body">
@ChildContent
</div>
<div class="card-footer">
<div class="container">
<div class="row">
<div class="col p-0">
<button class="col-6 btn btn-secondary btn-sm float-left" type="button"
disabled="@(ActiveStepIx == 0)" @onclick="GoBack">
Previous
</button>
</div>
<div class="col p-0">
<button class="col-6 btn btn-primary btn-sm float-right"
type="@(IsLastStep ? "submit" : "button")" @onclick="GoNext">
@(IsLastStep ? "Submit" : "Next")
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</CascadingValue>
@code
{
/// <summary>
/// List of <see cref="WizardStep"/> added to the Wizard
/// </summary>
protected internal List<WizardStep> Steps = new List<WizardStep>();
/// <summary>
/// The control Id
/// </summary>
[Parameter]
public string Id { get; set; }
/// <summary>
/// The ChildContent container for <see cref="WizardStep"/>
/// </summary>
[Parameter]
public RenderFragment ChildContent { get; set; }
/// <summary>
/// The Active <see cref="WizardStep"/>
/// </summary>
[Parameter]
public WizardStep ActiveStep { get; set; }
/// <summary>
/// The Index number of the <see cref="ActiveStep"/>
/// </summary>
[Parameter]
public int ActiveStepIx { get; set; }
/// <summary>
/// Determines whether the Wizard is in the last step
/// </summary>
public bool IsLastStep { get; set; }
/// <summary>
/// Sets the <see cref="ActiveStep"/> to the previous Index
/// </summary>
protected internal void GoBack()
{
if (ActiveStepIx > 0)
SetActive(Steps[ActiveStepIx - 1]);
}
/// <summary>
/// Sets the <see cref="ActiveStep"/> to the next Index
/// </summary>
protected internal void GoNext()
{
if (ActiveStepIx < Steps.Count - 1)
SetActive(Steps[(Steps.IndexOf(ActiveStep) + 1)]);
}
/// <summary>
/// Populates the <see cref="ActiveStep"/> the Sets the passed in <see cref="WizardStep"/> instance as the
/// </summary>
/// <param name="step">The WizardStep</param>
protected internal void SetActive(WizardStep step)
{
ActiveStep = step ?? throw new ArgumentNullException(nameof(step));
ActiveStepIx = StepsIndex(step);
if (ActiveStepIx == Steps.Count - 1)
IsLastStep = true;
else
IsLastStep = false;
}
/// <summary>
/// Retrieves the index of the current <see cref="WizardStep"/> in the Step List
/// </summary>
/// <param name="step">The WizardStep</param>
/// <returns></returns>
public int StepsIndex(WizardStep step) => StepsIndexInternal(step);
protected int StepsIndexInternal(WizardStep step)
{
if (step == null)
throw new ArgumentNullException(nameof(step));
return Steps.IndexOf(step);
}
/// <summary>
/// Adds a <see cref="WizardStep"/> to the WizardSteps list
/// </summary>
/// <param name="step"></param>
protected internal void AddStep(WizardStep step)
{
Steps.Add(step);
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
SetActive(Steps[0]);
StateHasChanged();
}
}
}
向导步骤
@if (Parent.ActiveStep == this)
{
<div id="step-@(Parent.StepsIndex(this) + 1)">
@ChildContent
</div>
}
@code {
/// <summary>
/// The <see cref="Wizard"/> container
/// </summary>
[CascadingParameter]
protected internal Wizard Parent { get; set; }
/// <summary>
/// The Child Content of the current <see cref="WizardStep"/>
/// </summary>
[Parameter]
public RenderFragment ChildContent { get; set; }
/// <summary>
/// The Name of the step
/// </summary>
[Parameter]
public string Name { get; set; }
protected override void OnInitialized()
{
Parent.AddStep(this);
}
}
和逻辑可以在本文Wizard
中阅读。据我了解,基本问题是通过单击普通“按钮”提交表单,这不应该发生。WizardStep