asp.net-coreblazorfluent-ui

Blazor Fluent UI Editform "EditForm requires either a Model parameter" error


I'm learning Blazor and I'm adapting Fluent UI because they are both made by Microsoft and I think they will work well.

So I'm changing the html editform below to a fluent editform. I'm applying it by looking at the form description on the Blazor Fluent UI site, and when I press the Login button, it says "EditForm requires either a Model parameter, or an EditContext parameter, please provide one of these." I get this error.

This works fine.

        <EditForm Model="@loginModel" OnValidSubmit="Authenticate" FormName="LoginForm">
            <DataAnnotationsValidator />
            <div class="mb-3 text-center flex-cloumn">
                <h3>LOGIN</h3>
            </div>
            <div class="mb-3">
                <label for="userName" class="form-label">User Name:</label>
                <InputText id="userName" @bind-Value="loginModel.UserName" class="form-control" />
                <ValidationMessage For="() => loginModel.UserName" class="text-danger" />
            </div>
            <div class="mb-3">
                <label for="password" class="form-label">Password:</label>
                <InputText id="password" @bind-Value="loginModel.Password" class="form-control" />
                <ValidationMessage For="() => loginModel.Password" class="text-danger" />
            </div>
            <div class="mb-3 text-center">
                <span class="text-danger">@errorMessage</span>
            </div>
            <button type="submit" class="btn btn-primary">Login</button>
        </EditForm>

@code {
    [SupplyParameterFromForm]
    public LoginViewModel loginModel { get; set; } = new();

    private string? errorMessage;

    private async Task Authenticate()
    {
        Console.WriteLine("Authenticate called");
    }
}

but it's not

        <FluentEditForm Model="@loginModel" OnValidSubmit="Authenticate" FormName="LoginForm" novalidate>
            <DataAnnotationsValidator />
            
            <FluentStack Orientation="Orientation.Vertical">
                <h3>LOGIN</h3>
                <div>
                    <FluentTextField Name="userName" @bind-Value="loginModel.UserName" Label="User Name" Required />
                    <FluentValidationMessage For="@(() => loginModel.UserName)"/>
                </div>
                <div>
                    <FluentTextField Name="password" @bind-Value="loginModel.Password" TextFieldType="TextFieldType.Password" Label="Password" Required />
                    <FluentValidationMessage For="@(() => loginModel.Password)"/>
                </div>
                <FluentButton Type="ButtonType.Submit" Appearance="Appearance.Accent">Login</FluentButton>
            </FluentStack>
        </FluentEditForm>

@code {
    [SupplyParameterFromForm]
    public LoginViewModel loginModel { get; set; } = new();

    private string? errorMessage;

    private async Task Authenticate()
    {
        Console.WriteLine("Authenticate called");
    }
}

I'm already providing a Model parameter in the FluentEditform tag, but I'm getting this error, so it doesn't make a lot of sense.

InvalidOperationException: EditForm requires either a Model parameter, or an EditContext parameter, please provide one of these.

Microsoft.AspNetCore.Components.Forms.EditForm.OnParametersSet()
Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
Microsoft.AspNetCore.Components.Rendering.ComponentState.SupplyCombinedParameters(ParameterView directAndCascadingParameters)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(ref DiffContext diffContext, int frameIndex)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(ref DiffContext diffContext, int newFrameIndex)
Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(ref DiffContext diffContext, int oldStartIndex, int oldEndIndexExcl, int newStartIndex, int newEndIndexExcl)
Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, out Exception renderFragmentException)
Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
Microsoft.AspNetCore.Components.Rendering.ComponentState.SupplyCombinedParameters(ParameterView directAndCascadingParameters)
Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters)
Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderRootComponentAsync(int componentId, ParameterView initialParameters)
Microsoft.AspNetCore.Components.HtmlRendering.Infrastructure.StaticHtmlRenderer.BeginRenderingComponent(IComponent component, ParameterView initialParameters)
Microsoft.AspNetCore.Components.Endpoints.EndpointHtmlRenderer.RenderEndpointComponent(HttpContext httpContext, Type rootComponentType, ParameterView parameters, bool waitForQuiescence)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
Microsoft.AspNetCore.Components.Endpoints.RazorComponentEndpointInvoker.RenderComponentCore(HttpContext context)
Microsoft.AspNetCore.Components.Endpoints.RazorComponentEndpointInvoker.RenderComponentCore(HttpContext context)
Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext+<>c+<<InvokeAsync>b__10_0>d.MoveNext()
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Antiforgery.Internal.AntiforgeryMiddleware.InvokeAwaited(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

Most of the answers I've found are just to make sure you've provided a Model or initialized the Model you provide, which I think is a pretty simple task and nothing more than a modification to the tutorial, but I don't know why.

I tried following this post, but I want to use httpcontext on static pages, so I was hoping there was another workaround.


Solution

  • There is a litte difference when using FluentTextField in SSR. You have to set the "Name" property from the model, such as Name="loginModel.UserName".

    ...
    <FluentTextField Name="loginModel.UserName" @bind-Value="loginModel.UserName" Label="User Name" Required />
    ...
    <FluentTextField Name="loginModel.Password" @bind-Value="loginModel.Password" TextFieldType="TextFieldType.Password" Label="Password" Required />
    ...
    

    Then the editform will work.