最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin7浏览0评论

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.

发布评论

评论列表(0)

  1. 暂无评论