保存按钮不会在第一次单击 Blazor Web Assembly 编辑表单时触发事件

Save button doesn't trigger event in the first click Blazor Web Assembly Edit form

所以,我有一个 EditForm 组件,其中 InputText 组件触发了 onFieldChanged 事件。另外,我有一个使用 OnValidSubmit EventCallback<EditContext> 的按钮,然后它会提交表单。问题是,如果 InputText 被聚焦并且我尝试单击“保存”按钮,它不会在第一次单击时触发,因为它首先调用 FieldChanged 事件,并且不调用 OnValidSubmit 事件,在第二次点击时它起作用。如果您单击按钮中的其他位置,它也有效,但在 InputText 之后单击不起作用。

我怎样才能让它在 fieldchangedEvent 之后调用 onValidSubmit

提前致谢。

编辑

EditFormBody组件:

@inherits ComponentBase 
@typeparam TItem
<div class="panel panel-primary">
<div class="panel-heading">
    <h4 class="panel-title">@Title</h4>
    <div class="panel-heading-btn">
        <a href="javascript:;" class="btn btn-xs btn-icon btn-circle" data-click="panel-expand"><i class="fa fa-expand"></i></a>
    </div>
</div>
<div class="panel-body">
    <div class="@BodyCss">

        @if (ShowWait)
        {
            <PleaseWait />
        }
        else
        {
            <EditForm  EditContext="@FormEditContext" OnValidSubmit="@OnSave">
                <DataAnnotationsValidator />
                <div class="form-group row">
                    <div class="col-12">
                        <Microsoft.AspNetCore.Components.Forms.ValidationSummary />
                    </div>
                </div>
                <div class="form-group row">
                    <div class="col-12">
                        @ChildContent

                    </div>
                </div>
               
                                <button type="submit" class="btn btn-primary mr-1" tabindex="51" disabled="@IsReadOnly">Save</button>
                           
                        </div>
                    
                </div>
            </EditForm>
        }
    </div>
</div>
@code {


[Parameter] public TItem Model { get; set; }

[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public RenderFragment LeftButtons { get; set; }


[Parameter] public bool IsReadOnly { get; set; }
[Parameter] public bool ShowCancel { get; set; } = true;

[Parameter] public EventCallback<EditContext> OnValidSubmit { get; set; }
[Parameter] public EventCallback Cancel { get; set; }
[Parameter] public EventCallback<string> PropertyChanged { get; set; }


private EditContext FormEditContext { get; set; }
private bool ShowWait { get; set; } = true;

protected override async Task OnParametersSetAsync ()
{
    if (Model != null)
    {
        FormEditContext = new EditContext(Model);
        FormEditContext.OnFieldChanged += OnChange;
        ShowWait = false;
    }
    await base.OnParametersSetAsync();
}
private void OnChange (object sender, FieldChangedEventArgs e)
{
    if (e.FieldIdentifier.FieldName != "CurrentValue")
        PropertyChanged.InvokeAsync(e.FieldIdentifier.FieldName);

}
private async Task OnSave (EditContext context)
{
    try
    {
     
        ShowWait = true;
        await OnValidSubmit.InvokeAsync(context);
        ShowWait = false;
    }
    catch (Exception ex)
    {
        ShowWait = false;
        await this.ShowErrorMessage(JS, Title, ex);
    }
   
}
private async Task Delete ()
{
    try
    {
        ShowWait = true;
        await OnValidSubmit.InvokeAsync(null);
        ShowWait = false;

        //await this.NavigateTo(ReturnUrl);
    }
    catch (Exception ex)
    {
        ShowWait = false;
        await this.ShowErrorMessage(JS, Title, ex);
    }
}}

调用组件的形式:

<EditFormBody Model="@CurrentObject" Mode="@Mode" Title="@Title" ReturnUrl="/administration/users" OnValidSubmit="@Save" Cancel="Cancel">
        <ChildContent>
            <InputText  @bind-Value="@CurrentObject.Email" />
        </ChildContent>
    </EditFormBody>

这是您的代码的基本版本。这适用于我的测试环境 - 从模板构建的 Blazor Server 项目。我查看了您的代码,目前看不到问题所在。我建议你使用这个准系统版本,检查它是否有效,然后在你破坏它之前构建它。祝你好运。

// BasicEditor.razor
@page "/basiceditor"
<BasicEditorCard EditContext="_EditContext" OnValidSubmit="ValidatedSubmit">
    <InputText @bind-Value="model.Email"></InputText>
</BasicEditorCard>
<div>@message</div>

@code {

    public class Model
    {
        public string Email { get; set; }
    }

    private EditContext _EditContext;

    private Model model { get; set; } = new Model() { Email = "me@you.com" };

    private string message = "Not yet clicked";

    protected override Task OnInitializedAsync()
    {
        _EditContext = new EditContext(model);
        return base.OnInitializedAsync();
    }

    private Task ValidatedSubmit(EditContext editContext)
    {
        message = $"clicked at {DateTime.Now.ToLongTimeString()}";
        return Task.CompletedTask;
    }
}
// BasicEditorCard.razor
<EditForm EditContext="EditContext" OnValidSubmit="ValidatedSubmit">
    <DataAnnotationsValidator />
    @ChildContent
    <button type="submit">Submit</button>
</EditForm>
<div>@message</div>

@code {

    [Parameter] public RenderFragment ChildContent { get; set; }

    [Parameter] public EditContext EditContext { get; set; }

    [Parameter] public EventCallback<EditContext> OnValidSubmit { get; set; }

    private string message = "No";

    private Task ValidatedSubmit()
    {
        OnValidSubmit.InvokeAsync(EditContext);
        message = $"clicked at {DateTime.Now.ToLongTimeString()}";
        return Task.CompletedTask;
    }
}

更新

你有两个问题:

逆逻辑
protected override async Task OnParametersSetAsync ()
{
    // should be if (Model is null)
    if (Model != null)
    {
        FormEditContext = new EditContext(Model);
        FormEditContext.OnFieldChanged += OnChange;
        ShowWait = false;
    }
    await base.OnParametersSetAsync();
}

你的逻辑是错误的!每次更改参数时,您都会创建一个新的 EditContext。

泛型

使用泛型也会导致问题。 EditContext 采用 object,因此您可以取消组件中的泛型,只需按如下方式声明 Model,在此过程中丢失 @typeparam TItem

[Parameter] public object Model { get; set; }

我的组件最终原型版本如下所示:

@implements IDisposable
<EditForm EditContext="EditContext" OnValidSubmit="ValidatedSubmit">
    <DataAnnotationsValidator />
    @ChildContent
    <button type="submit">Submit</button>
</EditForm>
<div>@message</div>
@code {

    [Parameter] public RenderFragment ChildContent { get; set; }
    [Parameter] public object Model { get; set; }
    [Parameter] public EventCallback<EditContext> OnValidSubmit { get; set; }
    private string message = "No";
    protected EditContext EditContext;

    protected override Task OnParametersSetAsync()
    {
        if (this.EditContext is null)
        {
            EditContext = new EditContext(Model);
            EditContext.OnFieldChanged += this.OnFieldChanged;
        }
        return base.OnParametersSetAsync();
    }

    private void OnFieldChanged(object sender, EventArgs e)
    {
        var x = true;
    }

    private Task ValidatedSubmit()
    {
        OnValidSubmit.InvokeAsync(EditContext);
        message = $"clicked at {DateTime.Now.ToLongTimeString()}";
        return Task.CompletedTask;
    }

    public void Dispose()
      => EditContext.OnFieldChanged -= this.OnFieldChanged;
}

在另一个主题上,您应该能够通过使用与您在等待中已经使用的技术类似的技术,在切换卡片内容时失去 Javascript。这是我的 UIShow 组件,应该可以为您指明正确的方向。 button/anchor 切换布尔值 属性?

@if (this.Show)
{
    @this.ChildContent
}

@code {
    [Parameter] public bool Show { get; set; }
    [Parameter] public RenderFragment ChildContent { get; set; }
}

我的 Blazor 口头禅之一s/commandments 是“你不能写 Javascript”!