blazor - FluentEditForm says that there is no data, despite data entered being there - Stack Overflow

My code, below, is a fluenteditform form. After I submit, it says that the fields still need to be fill

My code, below, is a fluenteditform form. After I submit, it says that the fields still need to be filled out even though I filled them out. What is wrong with my code?

@page "/movieform" 
@using Assignment10.Entities
@using System.ComponentModel.DataAnnotations

<h3>MovieForm</h3>

<FluentCard>
    <FluentEditForm FormName="MovieForm" Model="@movie">
        <DataAnnotationsValidator />
        <FluentValidationSummary />
        <FluentGrid>
            <FluentGridItem xs="12">
                <FluentTextField Name="MovieNameField" Id="movieNameField" @bind-Value="movie.MovieName" Label="Name: " Required/>
                <ValidationMessage For="@(() => movie.MovieName)" />
            </FluentGridItem>
            <FluentGridItem xs="12">
                <FluentTextField Name="MoviePublisherField" Id="moviePublisherField" @bind-Value="movie.Publisher" Label="Publisher: " Required/>
                <ValidationMessage For="@(() => movie.Publisher)" />

            </FluentGridItem>
            <FluentGridItem xs="12" >
                <FluentTextField Name="MovieDescriptionField" Id="movieDescriptionField" @bind-Value="movie.MovieDescription" Label="Description: " Required/>
                <ValidationMessage For="@(() => movie.MovieDescription)" />
            </FluentGridItem>
            <FluentGridItem xs="12" >
                <FluentButton Type="ButtonType.Submit" Appearance="Appearance.Accent">Submit</FluentButton>
            </FluentGridItem>
        </FluentGrid>
    </FluentEditForm>
</FluentCard>

@code {
    private Movie movie = new Movie(); 

}

My code, below, is a fluenteditform form. After I submit, it says that the fields still need to be filled out even though I filled them out. What is wrong with my code?

@page "/movieform" 
@using Assignment10.Entities
@using System.ComponentModel.DataAnnotations

<h3>MovieForm</h3>

<FluentCard>
    <FluentEditForm FormName="MovieForm" Model="@movie">
        <DataAnnotationsValidator />
        <FluentValidationSummary />
        <FluentGrid>
            <FluentGridItem xs="12">
                <FluentTextField Name="MovieNameField" Id="movieNameField" @bind-Value="movie.MovieName" Label="Name: " Required/>
                <ValidationMessage For="@(() => movie.MovieName)" />
            </FluentGridItem>
            <FluentGridItem xs="12">
                <FluentTextField Name="MoviePublisherField" Id="moviePublisherField" @bind-Value="movie.Publisher" Label="Publisher: " Required/>
                <ValidationMessage For="@(() => movie.Publisher)" />

            </FluentGridItem>
            <FluentGridItem xs="12" >
                <FluentTextField Name="MovieDescriptionField" Id="movieDescriptionField" @bind-Value="movie.MovieDescription" Label="Description: " Required/>
                <ValidationMessage For="@(() => movie.MovieDescription)" />
            </FluentGridItem>
            <FluentGridItem xs="12" >
                <FluentButton Type="ButtonType.Submit" Appearance="Appearance.Accent">Submit</FluentButton>
            </FluentGridItem>
        </FluentGrid>
    </FluentEditForm>
</FluentCard>

@code {
    private Movie movie = new Movie(); 

}
Share Improve this question edited Nov 18, 2024 at 16:19 Mike Brind 30.2k6 gold badges64 silver badges92 bronze badges asked Nov 16, 2024 at 20:27 user3776241user3776241 5439 silver badges21 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

you use <DataAnnotationsValidator /> - that's the reason your validator haven't receive data - it try to pass data to DataAnnotations infrastructure.

In my project I don't use libraries. Instead I use custom implementation of FluentValidationValidator component, and code looks like that:

<EditForm Model="Model" OnValidSubmit="OnValidSubmit">
    <FluentValidationValidator TValidator="MyModelValidator" />
    <ValidationSummary />

    // your inputs, with validation messages, like below:
    <ValidationMessage For="@(() => Model.Thought)" />
</EditForm>

@code{
    private EditContext editContext;
    private ValidationMessageStore messageStore;

    protected override void OnInitialized()
    {
        Model = new MyModel();

        editContext = new EditContext(Model);
        messageStore = new(editContext);

        base.OnInitialized();
    }

    private async Task OnValidSubmit()
    {
        // your save logic here
    }
}

And component itself (code found on stackoverflow):

public class FluentValidationValidator<TValidator> : ComponentBase where TValidator : IValidator, new()
{
    private readonly static char[] separators = new[] { '.', '[' };
    private TValidator validator;

    [CascadingParameter]
    private EditContext EditContext { get; set; }

    protected override void OnInitialized()
    {
        validator = new TValidator();
        var messages = new ValidationMessageStore(EditContext);

        /* Re-validate when any field changes or when the entire form   requests validation.*/
        EditContext.OnFieldChanged += (sender, eventArgs)
            => ValidateModel((EditContext)sender!, messages, false);

        EditContext.OnValidationRequested += (sender, eventArgs)
            => ValidateModel((EditContext)sender!, messages, true);
    }

    private void ValidateModel(EditContext editContext, ValidationMessageStore messages, bool submit)
    {
        if (submit)
            editContext.Properties["submitted"] = true;

        if (!editContext.Properties.TryGetValue("submitted", out _))
            return;

        var context = new ValidationContext<object>(editContext.Model);
        var validationResult = validator.Validate(context);
        messages.Clear();
        foreach (var error in validationResult.Errors)
        {
            var fieldIdentifier = ToFieldIdentifier(editContext, error.PropertyName);
            messages.Add(fieldIdentifier, error.ErrorMessage);
        }
        editContext.NotifyValidationStateChanged();
    }

    private static FieldIdentifier ToFieldIdentifier(EditContext editContext, string propertyPath)
    {
        var obj = editContext.Model;

        while (true)
        {
            var nextTokenEnd = propertyPath.IndexOfAny(separators);
            if (nextTokenEnd < 0)
            {
                return new FieldIdentifier(obj, propertyPath);
            }

            var nextToken = propertyPath.Substring(0, nextTokenEnd);
            propertyPath = propertyPath.Substring(nextTokenEnd + 1);

            object? newObj;
            if (nextToken.EndsWith("]"))
            {
                nextToken = nextToken.Substring(0, nextToken.Length - 1);
                var prop = obj.GetType().GetProperty("Item");
                var indexerType = prop!.GetIndexParameters()[0].ParameterType;
                var indexerValue = Convert.ChangeType(nextToken, indexerType);
                newObj = prop.GetValue(obj, [indexerValue]);
            }
            else
            {
                var prop = obj.GetType().GetProperty(nextToken);
                if (prop == null)
                {
                    throw new InvalidOperationException($"Could not find property named {nextToken} in object of type {obj.GetType().FullName}.");
                }
                newObj = prop.GetValue(obj);
            }

            if (newObj == null)
            {
                return new FieldIdentifier(obj, nextToken);
            }

            obj = newObj;
        }
    }
}

It works for me on several projects. Pros is you can extend component and add some custom logic, if necessary. Cons is you need to support it in your project. So if you decide to not support, you can try to use something from this link.

Hope it helpful.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745643870a4637855.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信