Валидация форм в Blazor Server

Мы уже частично познакомились с тем, как происходит валидация форм в Blazor, а также рассмотрели основные компоненты ввода для форм в Blazor. Сегодня мы более подробно рассмотрим процессы валидации форм с использованием компонентов Blazor, таких как DataAnnotationsValidator, ValidationSummary и ValidationMessage.

Про основы валидации модели в .NET C# можно также почитать статьи:
Валидация модели в C#
Валидация модели в C#. Атрибуты валидации

Варианты валидации формы в Blazor

В Blazor валидация формы может проводиться двумя способами:

  1. Валидация на уровне модели. Когда пользователь заполняет все элементы формы (InputText, InputSelect и т.д.) и пробует отправить форму на сервер. В этом случае, все найденные ошибки будут выведены на верху формы в виде списка. За такой вывод отвечает компонент ValidationSummary, работу с которым мы рассматривали здесь.
  2. Когда пользователь вводит в поле какое-либо значение и переводит фокус на другой элемент формы, то производится проверка конкретного поля на правильность ввода и, в случае ошибки, сообщение выводится непосредственно под полем с ошибкой. За такое поведение отвечает компонент ValidationMessage

Рассмотрим оба этих варианта валидации модели в Blazor Server более подробно.

Модель для приложения Blazor Server

Создадим новое приложение Blazor Server в Visual Studio 2022:

Blazor Server

В папке приложения создадим папку Models:

В этой папке создадим новый класс Person:

Содержимое файла Person.cs:

using System.ComponentModel.DataAnnotations;

namespace BlazorApp4.Models
{
    public class Person
    {
        public enum GenderEnum { Male, Female}


        [Required]
        [StringLength(50, MinimumLength =2, ErrorMessage ="Имя должно быть не менее 2-х символов и не более 50-ти")]
        public string Name { get; set; }
        [Required]
        [Range(1, 100, ErrorMessage = "Возраст должен быть от 1 до 100 лет")]
        public int Age { get; set; }
        [Required]
        public GenderEnum Gender { get; set; }
        [EmailAddress]
        public string Email { get; set; }
        [Phone]
        public string PhoneNumber { get; set; }

    }
}

Форма для модели

Для работы с созданной моделью создадим в папке Pages новый компонент Blazor с названием BlazorForm:

Содержимое файла BlazorForm.razor:

@page "/blazorform"

@using System.ComponentModel.DataAnnotations
@using BlazorApp4.Models

<h3>BlazorForm</h3>


<EditForm Model = "person">
    <DataAnnotationsValidator/>
    <ValidationSummary />
  <div class="row mb-3">
    <label for="name" class="col-sm-2 col-form-label">Имя</label>
    <div class="col-sm-10">
      <InputText @bind-Value="person.Name" class="form-control" id="name"/>
    </div>
  </div>
  <div class="row mb-3">
    <label for="age" class="col-sm-2 col-form-label">Возраст</label>
    <div class="col-sm-10">
      <InputNumber @bind-Value="person.Age"  class="form-control" id="age"/>
    </div>
  </div>
  
  <div class="row mb-3">
    <label for="gender" class="col-sm-2 col-form-label">Пол</label>
    <div class="col-sm-3">
      <InputSelect @bind-Value="person.Gender" id="gender" class="form-select">
            <option value="Male">Мужской</option>
            <option value="Female">Женский</option>
        </InputSelect>
    </div>
  </div>

  <div class="row mb-3">
    <label for="email" class="col-sm-2 col-form-label">E-mail</label>
    <div class="col-sm-10">
      <InputText type="email" @bind-Value="person.Email" class="form-control" id="email"/>
    </div>
  </div>
  <div class="row mb-3">
    <label for="phone" class="col-sm-2 col-form-label">Телефон</label>
    <div class="col-sm-10">
      <InputText type="email" @bind-Value="person.PhoneNumber" class="form-control" id="phone"/>
    </div>
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</EditForm>


@code {
    Person person = new();
}

В целом, в содержимом формы здесь для нас ничего нового нет — все моменты по работе с компонентами ввода типа InputText или InputSelect мы рассматривали здесь и здесь, а использование компонентов DataAnnotationsValidator и ValidationSummaryв этой статье. Единственное, то добавилось — это html-теги, использующие классы фреймворка bootstrap для того, чтобы форма имела более презентабельный вид. Теперь, если мы запустим приложение и перейдем на страницу /blazorform, то увидим вот такую форму:

Blazor Server Form

Если мы попытаемся отправить пустую форму, то, в соответствии с атрибутами валидации, которые мы определили в модели, мы получим следующий список ошибок:

Как мы уже знаем, за вывод всего списка обнаруженных ошибок формы в Blazor отвечает компонент ValidationSummary. Собственно, здесь мы реализовали первый вариант валидации модели, когда весь список ошибок выводится вверху формы. Теперь рассмотрим второй вариант валидации, когда проверка осуществляется по каждому полю формы в отдельности.

Компонент ValidationMessage

В отличие от ValidationSummary компонент ValidationMessage используется для вывода результата проверки какого-либо конкретного поля. При этом, текст ошибки выводится сразу после того, как проверяемое поле теряет фокус. Воспользоваться компонентом ValidationMessage можно следующим образом:

<InputText @bind-Value="person.Name" class="form-control" id="name"/>
<ValidationMessage For="@(() => person.Name)" />

В свойстве For мы используем лямбда-выражение и указываем какое поле будет проверяться. Добавим ValidationMessage к элементам нашей формы:

<EditForm Model = "person">
    <DataAnnotationsValidator/>
    
    <ValidationSummary />
    
  <div class="row mb-3">
    <label for="name" class="col-sm-2 col-form-label">Имя</label>
    <div class="col-sm-10">
      <InputText @bind-Value="person.Name" class="form-control" id="name"/>
      <ValidationMessage For="@(() => person.Name)" />
    </div>
  </div>
  <div class="row mb-3">
    <label for="age" class="col-sm-2 col-form-label">Возраст</label>
    <div class="col-sm-10">
      <InputNumber @bind-Value="person.Age"  class="form-control" id="age"/>
      <ValidationMessage For="@(() => person.Age)" />
    </div>
  </div>
  
  <div class="row mb-3">
    <label for="gender" class="col-sm-2 col-form-label">Пол</label>
    <div class="col-sm-3">
      <InputSelect @bind-Value="person.Gender" id="gender" class="form-select">
            <option value="Male">Мужской</option>
            <option value="Female">Женский</option>
        </InputSelect>
        <ValidationMessage For="@(() => person.Gender)" />
    </div>
  </div>

  <div class="row mb-3">
    <label for="email" class="col-sm-2 col-form-label">E-mail</label>
    <div class="col-sm-10">
      <InputText type="email" @bind-Value="person.Email" class="form-control" id="email"/>
      <ValidationMessage For="@(() => person.Email)" />
    </div>
  </div>
  <div class="row mb-3">
    <label for="phone" class="col-sm-2 col-form-label">Телефон</label>
    <div class="col-sm-10">
      <InputText type="email" @bind-Value="person.PhoneNumber" class="form-control" id="phone"/>
      <ValidationMessage For="@(() => person.PhoneNumber)" />
    </div>
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</EditForm>

Теперь запустим приложение и посмотрим как будут отображаться сообщения об ошибках, если мы, например, введем отрицательное значение возраста:

Как только вводится неверное значение, то сразу же выводится сообщение об ошибке под компонентом формы и эта же ошибка отображается в сводке сверху формы. Учитывая, что дублирование сообщений об ошибках не всегда требуется, мы можем воспользоваться для валидации формы в Blazor одним из наиболее подходящих для нас вариантов: либо с использованием ValidationSummary, либо с использованием ValidationMessage.

Использование свойства EditContext

Выше мы использовали свойство Model компонента EditForm для указания модели. Вместе с этим, для EditForm мы можем указать свойство EditContext, благодаря которому мы получаем большую гибкость работы с формами в Blazor. Перепишем код компонента BlazorForm следующим образом:

@page "/blazorform"

@using System.ComponentModel.DataAnnotations
@using BlazorApp4.Models

<h3>BlazorForm</h3>

<EditForm EditContext="editContext">
 <--Тут весь код формы-->
</EditForm>


@code {
    Person person = new();
    EditContext editContext;

    protected override void OnInitialized()
    {  
        editContext = new EditContext(person);
    }

}

Здесь мы переопредилили метод OnInitialized и создали в нем объект типа EditContext. В конструктор EditContext мы передали объект типа Person. У формы вместо свойства Model мы указали свойство EditContext которому и назначили созданный нами контекст. Теперь, если запустить приложение, то можно убедиться, что пока работа никак не изменилась — форма также валидируется и показывает ошибки ввода:

Но, как было сказано выше, использование EditContext дает большую гибкость в работе по валидации формы в Blazor. Рассмотрим несколько вариантов использования EditContext.

Отключение кнопки Submit

Сделаем так, чтобы в случае обнаружения ошибок в форме, кнопка Submit была не активна.

Первое: объявим переменную, которая будет хранить статус проверки формы:

@code {

    bool isFormValid = false;

    <--Остальной код-->

}

Второе: отредактируем код кнопки и добавим новы атрибут:

<button type="submit" class="btn btn-primary" disabled="@isFormValid">Submit</button>

Третье: обновим код компонента BlazorForm следующим образом:

@code {

    private bool isFormValid = false;

    private Person person = new();
    EditContext editContext;

    protected override void OnInitialized()
    {
        editContext = new EditContext(person);
        editContext.OnFieldChanged += FieldChanged;
        /*
            или, используя лямбда-выражение
            editContext.OnFieldChanged += (x, y) =>
            {
                isFormValid = !editContext.Validate();
            };
         */ 
    }


    private void FieldChanged(object sender, FieldChangedEventArgs args)
    {
        isFormValid = !editContext.Validate();
    }

}

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

Как можно убедиться, при ошибочном вводе какой-либо информации кнопка Submit становится не активной. Однако, при этом вся форма проходит валидацию, что, соответственно, влечет за собой вывод сразу всех ошибок в форме, даже, если пользователь ещё не начинал вводить данные в какое-либо поле.

Использование события OnSubmit

Когда мы используем свойство EditForm.Model то вызов OnSubmit сразу отправляет данные на сервер вне зависимости от того есть ли в форме ошибки или нет. С использованием EditForm.EditContext мы можем избежать отправки на сервер формы, содержащей ошибки следующим образом:

<EditForm EditContext="editContext" OnSubmit="SubmitForm">
    <DataAnnotationsValidator/>
    <ValidationSummary />
    <--тут код формы-->
</EditForm>


@code {

    private bool isFormValid = false;

    private Person person = new();
    EditContext editContext;

    protected override void OnInitialized()
    {
        editContext = new EditContext(person);
    }

    public void SubmitForm()
    {
        if (editContext.Validate())
        {
            //логика сохранения формы, например, в БД
        }
    }
}

Итого

Сегодня мы рассмотрели два варианта валидации форм в приложении Blazor Server. Результаты проверки могут выводится как в виде сводки (списка) вверху формы, так и по каждому полю формы в отдельности. Для более гибкого управления процессом валидации и отправки формы можно использовать свойство EditForm.EditContext.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии