Search code examples
razorblazorblazor-component

Blazor - How to make child component show validation messages?


I need to display validation messages if a nested-component is not properly filled in. The component is consumed by other parent-components and they need to get feedback on whether there are validation issues.

I have tried the following code for the nested-component and used the CanSubmit method. While the method correctly tells if there are validation problems the validation messages are not showing.

All the code below can be tested on blzorrepl: https://blazorrepl.com/repl/GvOQlvvv1789ra1G37

@if(editContext != null) {
    <EditForm EditContext="@editContext">
        <input type="text" @bind="testModel.Name" />
        <DataAnnotationsValidator />
        <ValidationSummary />
    </EditForm>
}

@code {
    [Parameter]
    public TestModel testModel
    {
        get { return (TestModel)editContext?.Model; }
        set { editContext = new EditContext(value); }
    }

    EditContext editContext;

    public bool CanSubmit()
    {
        return editContext.Validate();
    }
}

This is my parent-component code, a bit reduced but reproducing the problem:

<ChildComponent @ref="myTestComponent" testModel="testModel" />
<input type="button" @onclick="buttonClick" value="validate programmatically" />
<div>@testMessage</div>

@code {
    TestModel testModel = new TestModel();
    ChildComponent myTestComponent;
    string testMessage;

    void buttonClick()
    {
        testMessage = "not passed validation";

        if (myTestComponent.CanSubmit())
        {
            testMessage = "passed validation!";
        }
    }
}

The testMessage is only used to show the validation status.

What can I do to make parent-component cause the nested-component to show validation messages? I can only place the submit in the parent-component.

As it was requested, here is a more complete example of what I am doing, a list of items which can be edited inline as well as a form to add more instances. https://blazorrepl.com/repl/mlYwlQPm34bekYE824


Solution

  • I'll try to explain why your approach is not working and then suggest ways to solve it. I hope I understand your intentions correctly.

    First you need to change the <input type="text" ...> to <InputText @bind-Value="..." />

    When your method buttonClick is finished in your parent component, Blazor will call StateHasChanged on your component. It's part of the built-in logic of an EventHandler. This will trigger the component life cycle of your child component. During that cycle, the setter of your child component property testModel will be called, again. Blazor doesn't make any test for equality. (The only mighty check engine is the DiffierentialRenderTree at the end of a render cycle). That means a new EditContext will be created. This context, though, doesn't know about the validation error. Hence the message disappears. To prove that point, set a counter variable inside the setter and display it on the page. You will see this result.

    enter image description here.

    To avoid this scenario, you create the EditContext once, when the parameters are set, for instance.

    @code {
    
        [Parameter]
        public TestModel testModel { get; set; }
    
        EditContext editContext;
    
       protected override void OnParametersSet()
       {
           base.OnParametersSet();
           if(editContext == null)
           {
               editContext = new EditContext(testModel);
           }
       }
    
        public bool CanSubmit()
        {
            return editContext.Validate();
        }
    }
    

    If you need to update the model but preserve the validation state, write a comment, and we can go from there.

    enter image description here