Проверка формы редактирования, не применяющая недопустимый класс к пользовательскому компоненту

#c# #html #blazor #blazor-webassembly

Вопрос:

При использовании blazor важно создавать многоразовые пользовательские компоненты; это один из основных моментов использования Blazor.

Я создал базовый компонент ввода, который использует Bootstrap для своего CSS, как показано на рисунке.

 @inherits InputBase<string>

<InputText type="@Type"
           class="form-control"
           id="@_id"
           placeholder="@Placeholder"
           @bind-Value="CurrentValue"
           disabled="@Disabled"
           @attributes="AdditionalAttributes"/>
/* Additional properties below for placeholder, disabled, type, etc. they're just string properties */
 

Я помещаю это в форму редактирования, вот так…

 <EditForm Model="MyModel"
      OnValidSubmit="ViewModel.CreateAsync">
    <DataAnnotationsValidator />

<PrimaryInput @bind-Value="MyModel.Name"
              Placeholder="Name..."/>

</EditForm>
 

Проблема в том, что это не добавляет «недопустимый» класс к элементу. Отображаются как допустимые, так и измененные, но как только ввод становится недействительным, он не меняется на недопустимый, как это было бы с настраиваемым компонентом none. Это моя модель ниже, чтобы показать, что я добавил проверку в модель.

 public class MyModel
{
    [StringLength(5)]
    [Required]
    public string Name { get; set; }
}
 

Ниже приведено изображение того, что отображается:

введите описание изображения здесь

Это html-код, который генерируется Blazor…

 <input type="text" id="aa106d17-46d7-442c-be39-6c947f17186b" placeholder="Name..." aria-describedby="14b1189e-c3c5-4e1f-ae1d-330756147b44" class="form-control valid" aria-invalid="">
 

…как вы можете видеть, класс все еще действителен, но был применен недопустимый атрибут aria. Ниже приведен HTML — код для проверки ввода пользовательского компонента none…

 <input class="modified invalid" aria-invalid="">
 

…в этом случае применяется недопустимое значение. Что-то мешает классу переключиться на недопустимый в пользовательском компоненте.

Ответ №1:

Вам нужно запустить форму EditContext . Есть несколько способов сделать это — я опишу два из них.

Внутри вашего пользовательского компонента вы можете переопределить TryParseValueFromString и обработать там проверку — InputBase<> в нем есть эти свойства. Это может не иметь смысла, учитывая, что ваш тип string уже является а.

В противном случае вы можете сделать так, чтобы ваш пользовательский компонент содержал EditContext инъекцию в качестве каскадного параметра, а затем выполнить обратный вызов события при изменении, чтобы вызвать EditContext «ы NotifiedFieldChanged «.

Небольшой пример ниже этого второго примера:

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

[Parameter] 
private Expression<Func<string>> ValueExpression { get; set; }

private FieldIdentifier _field;

private void OnInitialized()
{
    _field = FieldIdentifier.Create(ValueExpression);
} 

private void OnInputChanged(ChangeEventArgs args)
{
    EditContext.NotifyFieldChanged(_fieldIdentifier);
}
 

Комментарии:

1. Не могли бы вы рассказать немного подробнее? Не совсем уверен, что я делаю, или есть какая-то документация, где это описано? Я пробую ваш второй пример и не совсем уверен, что мне делать. <input @bind-value="@Value" class="form-control" @onchange="OnInputChanged" /> Вот мой код, тогда у меня также есть пример кода, который вы опубликовали в своем ответе, но я не уверен, как все это должно выглядеть.

Ответ №2:

Я исправил это с помощью следующего кода в моем пользовательском компоненте….

 @inherits InputText

<InputText class="form-control"
 Value="@Value"
 ValueExpression="ValueExpression"
 ValueChanged="OnInputChanged" />
 

… немного странно наследовать входной текст с входным текстом внутри. Мой код, стоящий за этим, таков…

 private void OnInputChanged(string value)
{
    CurrentValueAsString = value;
    EditContext.NotifyFieldChanged(FieldIdentifier);
}
 

Затем в своем коде я помещаю этот компонент вот так….

 <TestInput @bind-Value="ViewModel.Menu.Name"/>
 

Это немного странная работа, но она выполняет свою работу и применяет правильные классы, когда она действительна/недействительна.

Ответ №3:

Вы наследуете от <InputBase> и помещаете InputText ( InputBase элемент управления) внутри него. Это действительно не имеет смысла.

Вот пример, демонстрирующий, как настроить стандарт InputText . В нем показано, как добавлять пользовательские атрибуты , один из способов обработки disabled , как введенные пользователем атрибуты добавляются к входным данным, и это обновляет значение при вводе с клавиатуры, а не при потере фокуса.

 @namespace Blazor.Starter.Components
@inherits InputText

    <input type="text" disabled="@Disabled" value="@this.CurrentValue" @oninput="OnInput" @ref="Element" id="@Id" @attributes="this.AdditionalAttributes" />

@code{

   [Parameter] public ElementReference? Element { get; set; }
   [Parameter] public string? Id { get; set; }
   [Parameter] public bool Disabled { get; set; }

    private void OnInput(ChangeEventArgs e)
        => this.CurrentValueAsString = e.Value.ToString();
}
 
 @page "/Test3"
<EditForm EditContext="@_editContext" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <label class="form-label">First Name</label>
    <CustomInput class="form-control" @bind-Value="this._formModel.FirstName" Id="mycontrol"></CustomInput>
    <label class="form-label">First Name</label>
    <CustomInput class="form-control" @bind-Value="this._formModel.FirstName" Id="mydisabledcontrol" Disabled="true"></CustomInput>
    <div class=" m-2 p-2">
        <button type="submit" class="btn btn-primary">New Person</button>
    </div>

    <div class="p3-m-3">Value: @_formModel.FirstName</div>

</EditForm>

@code {
    private EditContext? _editContext;
    private FormModel _formModel;

    private void HandleValidSubmit()
    {
        // handler
    }


    private class FormModel
    {
        [StringLength(5)][Required] public string FirstName { get; set; }
    }

    protected override Task OnInitializedAsync()
    {
        _formModel = new FormModel();
        _editContext = new EditContext(_formModel);
        return base.OnInitializedAsync();
    }
}
 
Ария Меняется

Смотрите два фрагмента html, чтобы узнать, когда ввод является допустимым/недопустимым.

 <input type="text" id="mycontrol" class="form-control" _bl_759b54c2-54a4-461f-8101-9661c9034c17>
 
 <input type="text" id="mycontrol" class="form-control" _bl_759b54c2-54a4-461f-8101-9661c9034c17 aria-invalid>
 

Комментарии:

1. Я ценю время, которое вы потратили на свой ответ, но это не решает проблему, с которой я сталкиваюсь, когда класс «недопустимый» не добавляется, даже если входное значение неверно.

2. Если вы настроите и запустите мой пример, вы увидите aria-invalid , как он появляется и исчезает как firstname есть/недействителен.

3. aria-invalid добавляется к моему тоже независимо от того, является ли он действительным или недействительным, в своем вопросе я говорю, как класс не меняется, чтобы отразить недопустимое/допустимое состояние ввода, и это то, что мне нужно. Чтобы я мог применять стили, основанные на допустимом/недопустимом состоянии входных данных.

4. InputBase добавляет/удаляет «aria-недопустимый» в/из AdditionalAttributes свойства на основе состояния проверки элемента управления. В моем коде выше он делает это правильно, добавляя его только в том случае, если поле пустое или содержит более 5 символов. Вы хотите сказать, что хотите применить пользовательский стиль на основе состояния проверки элемента управления?

5. Да, в стандартном вводном тексте, как показано в моем коде выше, класс valid или invalid применяется на основе проверки модели. Blazor имеет CSS-стиль для этого по умолчанию в файле app.css. Мой вопрос заключается в том, почему недопустимые и допустимые классы не изменяются должным образом в зависимости от состояния проверки в моем пользовательском компоненте.