保存按钮不会在第一次单击 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”!
所以,我有一个 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”!