Skip to content

Commit

Permalink
feat(docs) : new validation docs (#728)
Browse files Browse the repository at this point in the history
* Новая документация

* Доработки

* added examples

* added colors and some fixes

Co-authored-by: l.s.kramarov <[email protected]>
  • Loading branch information
agalaktionov and lskramarov authored Dec 7, 2021
1 parent b1e7c68 commit cf31315
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 16 deletions.
4 changes: 4 additions & 0 deletions packages/mosaic-dev/validation/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
</mc-tree-select>
</mc-form-field>

<mc-hint class="mc-error">
IP-адрес окончания диапазона должен быть больше, чем IP-адрес начала
</mc-hint>

<br><br>

<mc-form-field>
Expand Down
7 changes: 5 additions & 2 deletions packages/mosaic-examples/mosaic/validation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { McTextareaModule } from '@ptsecurity/mosaic/textarea';
import { McToolTipModule } from '@ptsecurity/mosaic/tooltip';

import { ValidationCompositeExample } from './validation-composite/validation-composite-example';
import { ValidationGlobalOneRequiredExample } from './validation-global-one-required/validation-global-one-required-example';
import { ValidationGlobalExample } from './validation-global/validation-global-example';
import { ValidationOnBlurExample } from './validation-on-blur/validation-on-blur-example';
import { ValidationOnTypeExample } from './validation-on-type/validation-on-type-example';
Expand All @@ -24,7 +25,8 @@ export {
ValidationGlobalExample,
ValidationOnBlurExample,
ValidationOnTypeExample,
ValidationSmallExample
ValidationSmallExample,
ValidationGlobalOneRequiredExample
};

const EXAMPLES = [
Expand All @@ -33,7 +35,8 @@ const EXAMPLES = [
ValidationGlobalExample,
ValidationOnBlurExample,
ValidationOnTypeExample,
ValidationSmallExample
ValidationSmallExample,
ValidationGlobalOneRequiredExample
];

@NgModule({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="docs-width">
<div class="docs-width layout-padding">
<form class="mc-form-horizontal"
[formGroup]="compositeFormGroup"
[class.validation-error]="compositeFormGroup.errors?.range"
Expand All @@ -15,7 +15,7 @@
[mcEnterDelay]="10"
#startTooltip="mcWarningTooltip"
[mcTrigger]="'manual'"
[mcPlacement]="popUpPlacements.Bottom">
[mcPlacement]="popUpPlacements.Top">
<input mcInput formControlName="start" (input)="onInput($event, startTooltip, 'start')">

<mc-hint *ngIf="compositeFormGroup.controls.start.invalid">
Expand All @@ -34,7 +34,7 @@
[mcEnterDelay]="10"
#endTooltip="mcWarningTooltip"
[mcTrigger]="'manual'"
[mcPlacement]="popUpPlacements.Bottom">
[mcPlacement]="popUpPlacements.Top">
<input mcInput formControlName="end" (input)="onInput($event, endTooltip, 'end')">

<mc-hint *ngIf="compositeFormGroup.controls.end.invalid">
Expand All @@ -45,7 +45,7 @@
</mc-form-field>
</div>

<mc-hint *ngIf="compositeFormGroup.errors?.range">
<mc-hint style="margin-top: 4px" class="mc-error" *ngIf="compositeFormGroup.errors?.range">
IP-адрес окончания диапазона должен быть больше, чем IP-адрес начала
</mc-hint>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.docs-width {
width: 400px;
}

.mc-alert {
margin-bottom: 16px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<div class="layout-margin">
<form class="mc-form-vertical margin docs-width" novalidate>
<div style="margin-bottom: 16px" class="mc-alert mc-alert_error" *ngIf="showError">
<i mc-icon="mc-info_16" [color]="themePalette.Error" class="mc-alert__icon"></i>
<div class="mc-body">
Заполните хотя бы одно из полей - <br> <b>Серия, Номер</b> или <b>Фамилия</b>
</div>
</div>

<div class="mc-form__fieldset">
<div class="mc-form__fieldset mc-horizontal">
<div class="mc-form__row flex-30">
<label class="mc-form__label">Серия</label>
<mc-form-field class="mc-form__control">
<input name="input" mcInput>
</mc-form-field>
</div>

<div class="mc-form__row flex-70">
<label class="mc-form__label">Номер</label>
<mc-form-field class="mc-form__control">
<input name="input" mcInput>
</mc-form-field>
</div>
</div>

<div class="mc-form__fieldset mc-horizontal">
<div class="mc-form__row flex-45">
<label class="mc-form__label">Имя</label>
<mc-form-field class="mc-form__control">
<input name="input" mcInput>

<mc-hint>Необязательно</mc-hint>
</mc-form-field>
</div>

<div class="mc-form__row flex-55">
<label class="mc-form__label">Отчество</label>
<mc-form-field class="mc-form__control">
<input name="input" mcInput>

<mc-hint>Необязательно</mc-hint>
</mc-form-field>
</div>
</div>

<div class="mc-form__row">
<label class="mc-form__label">Фамилия</label>
<mc-form-field class="mc-form__control">
<input name="input" mcInput>
</mc-form-field>
</div>
</div>

<div class="mc-form__row">
<button class="flex-40"
type="submit"
mc-button
[color]="themePalette.Primary"
[class.mc-progress]="inProgress"
[disabled]="disabled || inProgress"
(click)="checkForm()">
Отправить
</button>
</div>
</form>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Component } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { ThemePalette } from '@ptsecurity/mosaic/core';


/**
* @title validation-global
*/
@Component({
selector: 'validation-global-one-required-example',
templateUrl: 'validation-global-one-required-example.html',
styleUrls: ['validation-global-one-required-example.css']
})
export class ValidationGlobalOneRequiredExample {
themePalette = ThemePalette;

globalErrorForm: FormGroup;
showServerErrors = false;

inProgress = false;
disabled = false;
showError = false;

constructor() {
this.globalErrorForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
thirdName: new FormControl('')
});
}

submitGlobalErrorForm() {
this.showServerErrors = false;
this.inProgress = true;

setTimeout(
() => {
this.showServerErrors = true;
this.inProgress = false;
},
// tslint:disable-next-line:no-magic-numbers
1000
);
}

checkForm() {
this.inProgress = true;

setTimeout(
() => {
this.inProgress = false;
this.showError = true;
this.disabled = true;
},
// tslint:disable-next-line:no-magic-numbers
2000
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
[mcEnterDelay]="10"
#tooltip="mcWarningTooltip"
[mcTrigger]="'manual'"
[mcPlacement]="popUpPlacements.Bottom">
[mcPlacement]="popUpPlacements.Top">
<input mcInput formControlName="folderName" (input)="onInput($event)">

<mc-cleaner></mc-cleaner>

<mc-hint>Только буквы и цифры</mc-hint>
</mc-form-field>
</div>
</div>
Expand Down
8 changes: 8 additions & 0 deletions packages/mosaic/core/_core.scss
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,12 @@
.mc-theme-loaded-marker {
display: none;
}

.mc-error {
color: mc-color(map-get($theme, error), 500);
}

.mc-success {
color: mc-color(map-get($theme, success), 500);
}
}
127 changes: 118 additions & 9 deletions packages/mosaic/core/validation/validation.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,126 @@
### Валидация обязательных полей
<!-- example(validation-overview) -->
Хорошо спроектированный интерфейс помогает пользователю не совершать ошибок, а когда они возникают, валидация помогает верно исправить ошибку. В этом гайде разберем, что для этого нужно делать.

<br>
<div class="mc-alert mc-alert_warning">
<i class="mc mc-icon mc-error_16 mc-alert__icon"></i>
Все описанные ниже рекомендации не применяются к форме входа.
</div>


### Способы валидации
От хорошего к более плохому:
- защититься от ошибки,
- показывать под полями,
- показывать над формой.

#### Как защититься от ошибки
Примеры, когда интерфейс не даёт совершить ошибку

| <span class="mc-error">Плохо<span> | <span class="mc-success">Хорошо<span> |
|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Сообщать «Название обязательно» | Блокировать кнопку, пока не задано название |
| Сообщать «Название невалидно» | Автоматически заменить пробелы на _, чтобы все было валидно |
| Сообщать «Введите число» | Использовать контролы ввода чисел |

### Когда проверять на ошибки
Есть три способа проверить верность введенных значений:

1. Во время ввода значения
2. По уходу с поля (потере фокуса)
3. После отправки формы

#### Во время ввода значения
Иногда можно предотвратить неверный ввод значений, в таких случаях нужно запрещать ввод определённых символов, например букв в IP-адрес или в другой числовой формат. В этом случае запрещенные символы не вводятся и показывается желтый тултип на 3 секунды, после этого скрывается.

<!-- example(validation-on-type) -->

##### Диапазоны значений
Делайте так, чтобы нельзя было задать неправильно. Например, при вводе периода можно менять местами значения «С» и «По», если значение в «По» будут указаны раньше значения в «С».

#### По уходу с поля
Проверка на верность введеных значений в поле выполняется по потере фокуса (onblur), поля получают состояние ошибки. Поля получают нормальное состояние по изменению значения (onchange).

Если у поля есть подпись, то текст ошибки выводится под подписью

<br>
<div class="mc-alert mc-alert_warning">
<i class="mc mc-icon mc-error_16 mc-alert__icon"></i>
Пустые обязательные поля по onblur не получают состояние ошибки
</div>

### По уходу с поля
<!-- example(validation-on-blur) -->

### Глобальная ошибка
##### Составные поля
Если поля нуждаются в валидации [во время ввода значения](/validation/overview#Во-время-ввода-значения) или [по уходу с поля](/validation/overview#По-уходу-с-поля), то сначала выполняются эти проверки. После того как все значения валидны, срабатывает валидация на все поля, поля выделятся фоном и внизу пишется сообщение об ошибке.

<!-- example(validation-composite) -->

#### После отправки формы
##### Глобальная ошибка
При самой аккуратной валидации отдельных полей всегда что-то может пойти не так: пропадет соединение с БД, другой пользователь изменит данные системы и т. д. Если ошибка возникла или выявилась после нажатия на терминальные кнопки и не связана с ошибками в полях, то такая ошибка показывается алертом над формой и страница прокручивается до алерта с ошибкой.

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

<br>
<div class="mc-alert mc-alert_info">
<i class="mc mc-icon mc-info-o_16 mc-alert__icon"></i>
При повторной отправке формы все поля проверяются ещё раз. За время, пока пользователь дозаполнял форму, уникальность названия, например, могла пропасть.
</div>

<!-- example(validation-global) -->

### Обязательные поля на небольших формах
##### Ошибки в полях
Если не удалось сделать валидацию в полях во время ввода или по уходу с поля, то после отправки формы, страница прокручивается до первого поля с ошибкой и поле получает фокус.

<br>
<div class="mc-alert mc-alert_warning">
<i class="mc mc-icon mc-error_16 mc-alert__icon"></i>
Не блокируйте терминальную кнопку после отправки формы
</div>

### Обязательные поля
По умолчанию подразумевается, что все поля обязательные, обязательность никак не помечается. А необязательные как раз подписываются (или в плейсхолдере, или в подписи под полем).

<br>
<div class="mc-alert mc-alert_info">
<i class="mc mc-icon mc-info-o_16 mc-alert__icon"></i>
Поля «комментарий», «описание» почти всегда необязательные, воспринимаются таковыми. Их можно не подписывать как необязательные.
</div>
<br>

Состояние ошибки незаполненное обязательное поле получает только после отправки формы, в тексте ошибки сообщается (1), по каким причинам поле обязательно.

*(1) Иногда текстом ошибки можно пренебречь, если из контекста формы понятно, что поле обязательно для заполнение или текст ошибки получается очень длинным.*

Пустые обязательные поля не получают состояние ошибки при потере фокуса.

<br>
<div class="mc-alert mc-alert_dismissible">
<div>
<header>Совет</header>
Чтобы избежать проверки на незаполненность полей, можно использовать контролы с предустановленными значениями, которые нельзя оставить незаполненными (раскрывающийся список, радиокнопки)
</div>
</div>

<!-- example(validation-overview) -->

#### Обязательные поля на небольших формах
На небольших формах, где обязательные поля очевидны, терминальные кнопки лучше заблокировать до заполнения полей.

<br>
<div class="mc-alert mc-alert_warning">
<i class="mc mc-icon mc-error_16 mc-alert__icon"></i>
В больших формах не рекомендуется блокировать терминальные кнопки, может быть неочевидно, почему кнопка отправки формы неактивна.
</div>

<!-- example(validation-small) -->

### Во время ввода значения
<!-- example(validation-on-type) -->
#### Другие случаи
Бывают случаи, когда нужно заполнить хотя бы одно из обязательных полей. В этом случае после отправки формы, обязательные поля не получают состояние ошибки, но выводится алерт.

### Составные поля
<!-- example(validation-composite) -->
Текст алерта для каждого случая будет свой.

<!-- example(validation-global-one-required) -->

### Показ сообщений об ошибках вне форм
Иногда требуется показывать ошибки вне форм, например было запущено сканирование, но в процессе сервер вернул ошибку, в таком случае показывайте уведомление в центре уведомлений.
4 changes: 4 additions & 0 deletions packages/mosaic/form-field/_form-field-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,8 @@
.mc-form-field__hint {
@include mc-typography-level-to-styles($config, $form-field-hint-font-default);
}

.mc-hint {
@include mc-typography-level-to-styles($config, caption);
}
}

0 comments on commit cf31315

Please sign in to comment.