因此,我有一个EditForm
组件,它具有触发onFieldChanged
事件的InputText
组件。此外,我有一个使用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。
Generics使用泛型也是一个问题。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
组件,它应该为您指明正确的方向。用于切换布尔属性的按钮/锚点?
@if (this.Show)
{
@this.ChildContent
}
@code {
[Parameter] public bool Show { get; set; }
[Parameter] public RenderFragment ChildContent { get; set; }
}
我的Blazor咒语/戒律之一是";你不应该写Javascript"!