3

So I'm a little confused I think on how some submission logic works in Blazor Server (and possibly might be the same case with Blazor WebAssembly).

I have an EditForm with a field and a submit button (of type Submit):

    <EditForm EditContext="@_editContext" OnValidSubmit="@HandleValidSubmit">
        <DataAnnotationsValidator />
        <ValidationSummary />

        <label for="firstName" class="form-label">First Name</label>
        <InputText class="form-control" @bind-Value="_formModel.FirstName" />
        <button type="submit" class="btn btn-primary">New Person</button>

    </EditForm>


    @code {
    
    private void HandleValidSubmit()
    {
       System.Diagnostics.Debug.WriteLine("SUBMIT!");
    }
    
    private class FormModel
    {
        [Required(AllowEmptyStrings = false, ErrorMessage = "Provide a first name")]
        public string FirstName{ get; set; }

    }
    
}

In the browser, I do the following:

  1. Provide input that will evaluate to being invalid based on my FormModel and DataAnnotationsValidator and I am told so with a single button click. This is expected.
  2. I correct the value of the First Name text input, and with it still having focus in the browser, I click Submit
  3. All that happens is the DataValidation seems to have run (cool, that's always good), BUT clicking the Submit button did not ever appear to trigger my C# code that runs OnValidSubmit. (As you can see in my example, I test with Debug.WriteLine

Is there a way to avoid this WHILE keeping the EditForm using OnSubmit/OnInvalidSubmit/OnValidSubmit and buttons with type="submit"?

(I read that there is a little bit of a difference when using buttons of type submit vs of type button in Blazor and State updates...no idea if that is a factor here)

From the user's point of view, they are pressing the button twice for a single action. Which of course can feel a little odd or confusing.

From my testing, this seems to be the case when DataAnnotationsValidator is involved, and this partially makes sense up until two button presses on the client are required to actually hit my C# code. (i.e. I understand that Data Validation is occurring when focus changes)

I feel like I'm partially misunderstanding something, and partially missing some extra code or setup in my form to avoid this.

Is there a way to do what I'm looking to do here, while keeping the DataAnnotationsValidator ?

Thanks in advance for any help!

1 Answer 1

0

I think what's happening is that when you "click" on the button (with a validation message displayed) what first happens is the input control loses focus. This causes a validation event - the data entry passes validation, the ValidationSummary updates and disappears. The render event shunts the button up the page, so when the the browser applies the click event, it's on a blank bit of the screen, not the button. In the test code below I've added a submit button above ValidationSummary which works because it doesn't move. It happens so quickly you miss it!

One fix for this is to change the behaviour of the input to validate on data entry rather that losing focus.

Here's a custom InputText control:

@namespace MyNameSpace
@inherits InputText

<input type="text" value="@this.CurrentValue" @oninput="OnInput" @ref="Element" />

@code{

    public ElementReference? Element { get; set; }

    private void OnInput(ChangeEventArgs e)
    => this.CurrentValueAsString = e.Value.ToString();
}

The only different between it and the original in that the response event is now set to "oninput" rather that "onchange".

The test page is shown below. Both versions of the control are displayed so you can see the different behaviours.

@page "/Test2"
<EditForm EditContext="@_editContext" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="HandleInValidSubmit">

    <DataAnnotationsValidator />

    <div class=" m-2 p-2">
        <button type="submit" class="btn btn-primary">New Person</button>
    </div>

    <ValidationSummary />

    <label class="form-label">First Name (Only Updates on Exit)</label>
    <InputText class="form-control" @bind-Value="this._formModel.FirstName"></InputText>

    <label class="form-label">First Name (Updates on Typing)</label>
    <InputTextOnInput class="form-control" @bind-Value="this._formModel.FirstName"></InputTextOnInput>

    <button type="submit" class="btn btn-primary">New Person</button>

</EditForm>

<div class="m-3 p-3">@_submitType</div>

@code {
    private EditContext? _editContext;
    private FormModel _formModel;
    private string _submitType;

    private void HandleValidSubmit()
    {
        _submitType = "VALID SUBMIT!";
        System.Diagnostics.Debug.WriteLine("VALID SUBMIT!");
    }

    private void HandleInValidSubmit()
    {
        _submitType = "INVALID SUBMIT!";
        System.Diagnostics.Debug.WriteLine("INVALID SUBMIT!");
    }

    private class FormModel
    {
        [Required(AllowEmptyStrings = false, ErrorMessage = "Provide a first name")]
        public string FirstName { get; set; }

    }

    protected override Task OnInitializedAsync()
    {
        _formModel = new FormModel();
        _editContext = new EditContext(_formModel);
        return base.OnInitializedAsync();
    }

}

Here's the link to the source code for the input controls

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.