Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Pass array of RuleSets to Options from component parameter #225

Open
mohaaron opened this issue Apr 15, 2024 · 2 comments
Open

[Bug] Pass array of RuleSets to Options from component parameter #225

mohaaron opened this issue Apr 15, 2024 · 2 comments
Labels
Bug Something isn't working Triage Issue needs to be triaged

Comments

@mohaaron
Copy link

mohaaron commented Apr 15, 2024

Describe the bug
In my form component where I'm using FluentValidationValidator I have a parameter that I'm using to apply the RuleSets that I want to use for the for validation. This is not working for some reason.

<FluentValidationValidator Options="@(options => options.IncludeRuleSets(RuleSets.ToArray()))" />

[Parameter]
public List<string> RuleSets { get; set; } = new();

I can only get the RuleSet correctly applied by passing a static string array as follows.

<FluentValidationValidator Options="@(options => options.IncludeRuleSets("Rule1", "Rule2"))" />

Expected behavior
Passing a Parameter array to the IncludeRuleSets method correctly applies the rules.

Hosting Model (is this issue happening with a certain hosting model?):

  • Blazor Server

Here is the complete code that I'm trying to make work that is wrapping a TelerikForm so that I can reuse it across many forms.

@using FluentValidation
@using FluentValidation.Internal
@typeparam TModel where TModel : class
@inherits FormComponentBase<TModel>

<TelerikForm Class="@Class"
                EditContext="EditContext"
                ValidationMessageType="FormValidationMessageType.Tooltip"
                OnUpdate="FieldUpdated"
                OnValidSubmit="ValidSubmit">
    <FormValidation>
        <FluentValidationValidator Options="@(options => SetValidationStrategy(options))" />
    </FormValidation>
    <FormItems>
        @ChildContent
    </FormItems>
    <FormButtons>
        @if (IsEditMode)
        {
            <div class="account-buttons">
                <ActionButton ActionText="Save Changes" ActionType="ActionType.Primary" ActionEnabled="@IsValidated" IsBusy="@IsSaving" />
                <ActionButton ActionText="Cancel" ActionType="ActionType.Link" ActionClick="@(() => IsEditMode = false)" />
            </div>
        }
    </FormButtons>
</TelerikForm>

@code
{
    [Parameter, EditorRequired]
    public RenderFragment ChildContent { get; set; } = default!;

    [Parameter]
    public string Class { get; set; } = string.Empty;

    [Parameter]
    public List<string> RuleSets { get; set; } = new();

    private void SetValidationStrategy(ValidationStrategy<object> strategy)
    {
        if (RuleSets.Count() > 0)
        {
            strategy.IncludeRuleSets(RuleSets.ToArray());
        }
    }
}
@mohaaron mohaaron added Bug Something isn't working Triage Issue needs to be triaged labels Apr 15, 2024
@mohaaron
Copy link
Author

mohaaron commented Apr 16, 2024

Maybe I've figured out something about how the RuleSets are supposed to be setup. Does it make sense that I have to put the RuleSet in both the parent validator CustomerProfileValidator, and the child validators for the above code to work? I've found that I get very strange behavior if I don't put the rule in both the parent and child validators. On the screen the form fields when entering an incorrect value will blip a red outline around the text box for a split second and then validation returns true instead of false.

namespace Portal.Shared.Validators;
public class CustomerProfileValidator : AbstractValidator<CustomerProfile>
{
    public CustomerProfileValidator()
    {
        RuleSet("Profile", () =>
        {
            RuleFor(profile => profile.EmploymentStartDate)
                .NotNull().NotEmpty()
                .WithMessage("Start date must be selected");
        });

        RuleSet("PhoneNumber", () =>
        {
            RuleForEach(profile => profile.PhoneNumbers)
                .SetValidator(new PhoneNumberValidator());
        });

        RuleSet("Email", () =>
        {
            RuleForEach(profile => profile.EmailAddresses)
                .SetValidator(new EmailAddressValidator());
        });
    }
}

namespace Portal.Shared.Validators;
public class PhoneNumberValidator : AbstractValidator<PhoneNumber>
{
    public PhoneNumberValidator()
    {
        RuleSet("PhoneNumber", () =>
        {
            RuleFor(phone => phone.Number)
            .MaximumLength(25).WithMessage("Maximum length is 25 characters")
            .Matches(@"^[\+\d]?(?:[\d\-\s()]*)$").WithMessage("Numbers can only contain numbers, dashes, and spaces");
        });
    }
}

namespace Portal.Shared.Validators;
public class EmailAddressValidator : AbstractValidator<EmailAddress>
{
    public EmailAddressValidator()
    {
        RuleSet("Email", () =>
        {
            RuleFor(email => email.Email)
            .MaximumLength(100).WithMessage("Maximum length is 100 characters")
            .Matches(@"^[a-z0-9_\.-]+\@[\da-z\.-]+\.[a-z\.]{2,6}$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
                .WithMessage("Email is not in the correct format");
        });
    }
}

@mohaaron
Copy link
Author

mohaaron commented Apr 18, 2024

I've created the linked repo as an example. I am trying to recreate the issue and at this point I've not be able to repro it. I am now seeing a different issue related to RuleSets in that the RuleSets are not being enforced. In the current state of the code the Email validationshould be ignored and only the Customer validation should be running but it's not. I don't understand why RuleSets are behaving so strangely.

https://github.com/mohaaron/BlazoredCollectionValidation

  1. Navigate to Email validation menu item.
  2. Click Add Email button to add a blank text box.
  3. Click Submit button. You see that the first and last name inputs fail validation, and nothing happens with the Email input.
  4. Now enter random characters into the Email input and click submit. The red border around the input and the validation message show up for a split second and then the input returns to a green border.
  5. Add some more random characters to the Email input and now the red border and validation message stay.

I expected the Email input to be ignored completely given the RuleSet is using only "Customer".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working Triage Issue needs to be triaged
Projects
None yet
Development

No branches or pull requests

1 participant