Проверка 2 компонентов имеют одинаковое значение - PullRequest
2 голосов
/ 18 октября 2019

Я написал компонент PIN, который состоит из 4 полей ввода (так как он будет использоваться повторно в нескольких местах)

<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinOne"/>
<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinTwo"/>
<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinThree"/>
<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinFour" @oninput="Completion"/>

@code{
    [Parameter]
    public EventCallback<string> Completed { get; set; }

    private string _pinOne;
    private string _pinTwo;
    private string _pinThree;
    private string _pinFour;

    private void Completion(ChangeEventArgs e)
    {
        _pinFour = e.Value.ToString();

        Completed.InvokeAsync(_pinOne + _pinTwo + _pinThree + _pinFour);
    }
}

Затем я создал другой компонент, который использует 2 изэти компоненты ввода PIN-кода

<PinComponent Completed="@PinCompleted"></PinComponent>
<PinComponent Completed="@ConfirmationPinCompleted"></PinComponent>
@code {
    private string _pin;
    private string _confirmationPin;

    private bool _valid = false;

    private void PinCompleted(string pin)
    {
        _pin = pin;
    }

    private void ConfirmationPinCompleted(string pin)
    {
        _confirmationPin = pin;

        if (_pin.Equals(_confirmationPin))
        {
            _valid = true;
        }
    }
}

Можно ли использовать Blaid-ValidationMessage, чтобы эти два компонента имели одинаковое значение?

Ответы [ 2 ]

1 голос
/ 18 октября 2019

Передайте значение и результат проверки на ваш PinComponent и заставьте этот компонент отображать ошибки проверки.

<PinComponent Completed="@PinCompleted"></PinComponent>
<PinComponent Completed="@ConfirmationPinCompleted" ValidationMessage="@validationMessage"></PinComponent>

@code {
    private string _pin;
    private string _confirmationPin;

    private bool _valid = false;

    private string ValidationMessage => _valid ? string.Empty : "PIN does not match";

    private void PinCompleted(string pin)
    {
        _pin = pin;
    }

    private void ConfirmationPinCompleted(string pin)
    {
        _confirmationPin = pin;

        if (_pin.Equals(_confirmationPin))
        {
            _valid = true;
        }
    }
}

, если вы хотите использовать проверку форм Blazor *

class PinModel
{
    [Required]
    public string Pin {get;set;}

    [Required]
    [PinTheSame]
    public string PinConfirmation {get;set;}
}

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class PinTheSameAttirbute: ValidationAttribute
{

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
        if (value == null) return new ValidationResult("A pin is required.");

        // Make sure you change PinModel to whatever  the actual name is
        if ((validationContext.ObjectType.Name != "PinModel") 
             return new ValidationResult("This attribute is being used incorrectly.");
        if (((PinModel)validationContext.ObjectInstance).ConfirmPin != value.ToString())
            return new ValidationResult("Pins must match.");

        return ValidationResult.Success;
        }

}

и передатьЗначения как модель

<EditForm Model="@Model">
    <PinComponent Value="@Pin"></PinComponent>
    <PinComponent Value="@ConfirmationPin"></PinComponent>
</EditForm>

Последний подход не полностью завершен, но должен дать вам представление о направлении.

0 голосов
/ 24 октября 2019

Хорошо, я решил использовать FluentValidation, так как по какой-то причине я не мог заставить настраиваемые атрибуты (или встроенный атрибут Compare) работать вообще

PinComponent.Razor

<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinOne"/>
<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinTwo"/>
<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinThree"/>
<input class="pinBox" type="password" maxlength="1" size="1" onkeypress='return event.charCode >= 48 && event.charCode <= 57' required @bind="@_pinFour" @oninput="Completion"/>

@code{
    private string _value;
    [Parameter]
    public string Value
    {
        get { return Value; }
        set
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                _pinOne = null;
                _pinTwo = null;
                _pinThree = null;
                _pinFour = null;
            }

            _value = value;
        }
    }

    [Parameter]
    public EventCallback<string> ValueChanged { get; set; }

    private string _pinOne;
    private string _pinTwo;
    private string _pinThree;
    private string _pinFour;

    private void Completion(ChangeEventArgs e)
    {
        _pinFour = e.Value.ToString();

        ValueChanged.InvokeAsync(_pinOne + _pinTwo + _pinThree + _pinFour);
    }
}

PinConfirmationComponent.Razor

@using Application.Validation

<EditForm Model="@_model" OnValidSubmit="@OnValidSubmit" OnInvalidSubmit="@OnInvalidSubmit">
    <div class="pinContainer">
        <PinComponent @bind-Value="_model.Pin"></PinComponent>
        <PinComponent @bind-Value="_model.PinConfirmation"></PinComponent>
    </div>
    <FluentValidationValidator />
    <ValidationSummary />
    <input id="btnSubmit" class="btn btnFont" type="submit" value="Register PIN" style="margin-top: 5px;" />
</EditForm>

@code {
    private PinModel _model = new PinModel();

    void OnValidSubmit()
    {

    }

    void OnInvalidSubmit()
    {
        _model.Pin = null;
        _model.PinConfirmation = null;
        StateHasChanged();
    }
}

PinModel.cs

public class PinModel
{
    public string Pin { get; set; }

    public string PinConfirmation { get; set; }
}

После этого примера репо Я использовал FluentValidation

EditContextFluentValidationExtensions. cs

public static class EditContextFluentValidationExtensions
    {
        public static EditContext AddFluentValidation(this EditContext editContext)
        {
            if (editContext == null)
            {
                throw new ArgumentNullException(nameof(editContext));
            }

            var messages = new ValidationMessageStore(editContext);

            editContext.OnValidationRequested +=
                (sender, eventArgs) => ValidateModel((EditContext)sender, messages);

            editContext.OnFieldChanged +=
                (sender, eventArgs) => ValidateField(editContext, messages, eventArgs.FieldIdentifier);

            return editContext;
        }

        private static void ValidateModel(EditContext editContext, ValidationMessageStore messages)
        {
            var validator = GetValidatorForModel(editContext.Model);

            if (validator == null)
                return;

            var validationResults = validator.Validate(editContext.Model);

            messages.Clear();
            foreach (var validationResult in validationResults.Errors)
            {
                messages.Add(editContext.Field(validationResult.PropertyName), validationResult.ErrorMessage);
            }

            editContext.NotifyValidationStateChanged();
        }

        private static void ValidateField(EditContext editContext, ValidationMessageStore messages, in FieldIdentifier fieldIdentifier)
        {
            var properties = new[] { fieldIdentifier.FieldName };
            var context = new ValidationContext(fieldIdentifier.Model, new PropertyChain(), new MemberNameValidatorSelector(properties));

            var validator = GetValidatorForModel(fieldIdentifier.Model);

            if (validator == null)
                return;

            var validationResults = validator.Validate(context);

            messages.Clear(fieldIdentifier);

            foreach (var validationResult in validationResults.Errors)
            {
                messages.Add(editContext.Field(validationResult.PropertyName), validationResult.ErrorMessage);
            }

            editContext.NotifyValidationStateChanged();
        }

        private static IValidator GetValidatorForModel(object model)
        {
            var abstractValidatorType = typeof(AbstractValidator<>).MakeGenericType(model.GetType());
            var modelValidatorType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.IsSubclassOf(abstractValidatorType));

            if (modelValidatorType == null)
                return null;

            var modelValidatorInstance = (IValidator)Activator.CreateInstance(modelValidatorType);

            return modelValidatorInstance;
        }
    }

FluentValidationValidator.cs

public class FluentValidationValidator : ComponentBase
    {
        [CascadingParameter] 
        EditContext CurrentEditContext { get; set; }

        protected override void OnInitialized()
        {
            if (CurrentEditContext == null)
            {
                throw new InvalidOperationException($"{nameof(FluentValidationValidator)} requires a cascading " +
                    $"parameter of type {nameof(EditContext)}. For example, you can use {nameof(FluentValidationValidator)} " +
                    $"inside an {nameof(EditForm)}.");
            }

            CurrentEditContext.AddFluentValidation();
        }
    }

PinValidator.cs

public class PinValidator : AbstractValidator<PinModel>
    {
        public PinValidator()
        {
            RuleFor(p => p.Pin).NotNull().Matches("^[0-9]{4}$");
            RuleFor(p => p).Must(PinsAreSame)
                .WithMessage("PINs must be the same");
        }

        private bool PinsAreSame(PinModel pinModel)
        {
            return (pinModel.Pin.Equals(pinModel.PinConfirmation));
        }
    }
...