1

根据本文,我正在使用向导组件逻辑创建一个多步骤 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

4

1 回答 1

2

请尝试在下一个按钮上使用此设置:

<button @onclick:stopPropagation=true/>

HTML DOM(文档对象模型)中的事件冒泡,在这种情况下,按钮单击事件冒泡并到达提交按钮并导致提交,如果我们不希望事件冒泡到父 DOM,那么我们应该抑制他们。

于 2022-02-03T09:36:19.840 回答