diff options
Diffstat (limited to 'client/src/app/shared')
6 files changed, 126 insertions, 22 deletions
diff --git a/client/src/app/shared/forms/form-reactive.ts b/client/src/app/shared/forms/form-reactive.ts index e7764d069..441ec8203 100644 --- a/client/src/app/shared/forms/form-reactive.ts +++ b/client/src/app/shared/forms/form-reactive.ts | |||
@@ -1,40 +1,48 @@ | |||
1 | import { FormGroup } from '@angular/forms' | 1 | import { FormGroup } from '@angular/forms' |
2 | import { BuildFormArgument, BuildFormDefaultValues, FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' | ||
3 | |||
4 | export type FormReactiveErrors = { [ id: string ]: string } | ||
5 | export type FormReactiveValidationMessages = { | ||
6 | [ id: string ]: { | ||
7 | [ name: string ]: string | ||
8 | } | ||
9 | } | ||
2 | 10 | ||
3 | export abstract class FormReactive { | 11 | export abstract class FormReactive { |
4 | abstract form: FormGroup | 12 | protected abstract formValidatorService: FormValidatorService |
5 | abstract formErrors: Object | ||
6 | abstract validationMessages: Object | ||
7 | 13 | ||
8 | abstract buildForm (): void | 14 | form: FormGroup |
15 | formErrors: FormReactiveErrors | ||
16 | validationMessages: FormReactiveValidationMessages | ||
9 | 17 | ||
10 | protected onValueChanged (data?: any) { | 18 | buildForm (obj: BuildFormArgument, defaultValues: BuildFormDefaultValues = {}) { |
11 | for (const field in this.formErrors) { | 19 | const { formErrors, validationMessages, form } = this.formValidatorService.buildForm(obj, defaultValues) |
12 | // clear previous error message (if any) | ||
13 | this.formErrors[field] = '' | ||
14 | const control = this.form.get(field) | ||
15 | 20 | ||
16 | if (control && control.dirty && !control.valid) { | 21 | this.form = form |
17 | const messages = this.validationMessages[field] | 22 | this.formErrors = formErrors |
18 | for (const key in control.errors) { | 23 | this.validationMessages = validationMessages |
19 | this.formErrors[field] += messages[key] + ' ' | 24 | |
20 | } | 25 | this.form.valueChanges.subscribe(data => this.onValueChanged(false)) |
21 | } | ||
22 | } | ||
23 | } | 26 | } |
24 | 27 | ||
25 | // Same as onValueChanged but force checking even if the field is not dirty | 28 | protected onValueChanged (forceCheck = false) { |
26 | protected forceCheck () { | ||
27 | for (const field in this.formErrors) { | 29 | for (const field in this.formErrors) { |
28 | // clear previous error message (if any) | 30 | // clear previous error message (if any) |
29 | this.formErrors[field] = '' | 31 | this.formErrors[ field ] = '' |
30 | const control = this.form.get(field) | 32 | const control = this.form.get(field) |
31 | 33 | ||
32 | if (control && !control.valid) { | 34 | // Don't care if dirty on force check |
33 | const messages = this.validationMessages[field] | 35 | const isDirty = control.dirty || forceCheck === true |
36 | if (control && isDirty && !control.valid) { | ||
37 | const messages = this.validationMessages[ field ] | ||
34 | for (const key in control.errors) { | 38 | for (const key in control.errors) { |
35 | this.formErrors[field] += messages[key] + ' ' | 39 | this.formErrors[ field ] += messages[ key ] + ' ' |
36 | } | 40 | } |
37 | } | 41 | } |
38 | } | 42 | } |
39 | } | 43 | } |
44 | |||
45 | protected forceCheck () { | ||
46 | return this.onValueChanged(true) | ||
47 | } | ||
40 | } | 48 | } |
diff --git a/client/src/app/shared/forms/form-validators/form-validator.service.ts b/client/src/app/shared/forms/form-validators/form-validator.service.ts new file mode 100644 index 000000000..5c3d3e4bd --- /dev/null +++ b/client/src/app/shared/forms/form-validators/form-validator.service.ts | |||
@@ -0,0 +1,65 @@ | |||
1 | import { FormBuilder, FormControl, FormGroup, ValidatorFn } from '@angular/forms' | ||
2 | import { Injectable } from '@angular/core' | ||
3 | import { FormReactiveErrors, FormReactiveValidationMessages } from '@app/shared/forms/form-reactive' | ||
4 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
5 | |||
6 | export type BuildFormArgument = { | ||
7 | [ id: string ]: { | ||
8 | VALIDATORS: ValidatorFn[], | ||
9 | MESSAGES: { [ name: string ]: string } | ||
10 | } | ||
11 | } | ||
12 | export type BuildFormDefaultValues = { | ||
13 | [ name: string ]: string | string[] | ||
14 | } | ||
15 | |||
16 | @Injectable() | ||
17 | export class FormValidatorService { | ||
18 | |||
19 | constructor ( | ||
20 | private formBuilder: FormBuilder, | ||
21 | private i18n: I18n | ||
22 | ) {} | ||
23 | |||
24 | buildForm (obj: BuildFormArgument, defaultValues: BuildFormDefaultValues = {}) { | ||
25 | const formErrors: FormReactiveErrors = {} | ||
26 | const validationMessages: FormReactiveValidationMessages = {} | ||
27 | const group: { [key: string]: any } = {} | ||
28 | |||
29 | for (const name of Object.keys(obj)) { | ||
30 | formErrors[name] = '' | ||
31 | |||
32 | const field = obj[name] | ||
33 | if (field && field.MESSAGES) validationMessages[name] = field.MESSAGES | ||
34 | |||
35 | const defaultValue = defaultValues[name] || '' | ||
36 | |||
37 | if (field && field.VALIDATORS) group[name] = [ defaultValue, field.VALIDATORS ] | ||
38 | else group[name] = [ defaultValue ] | ||
39 | } | ||
40 | |||
41 | const form = this.formBuilder.group(group) | ||
42 | return { form, formErrors, validationMessages } | ||
43 | } | ||
44 | |||
45 | updateForm ( | ||
46 | form: FormGroup, | ||
47 | formErrors: FormReactiveErrors, | ||
48 | validationMessages: FormReactiveValidationMessages, | ||
49 | obj: BuildFormArgument, | ||
50 | defaultValues: BuildFormDefaultValues = {} | ||
51 | ) { | ||
52 | for (const name of Object.keys(obj)) { | ||
53 | formErrors[name] = '' | ||
54 | |||
55 | const field = obj[name] | ||
56 | if (field && field.MESSAGES) validationMessages[name] = field.MESSAGES | ||
57 | |||
58 | const defaultValue = defaultValues[name] || '' | ||
59 | |||
60 | if (field && field.VALIDATORS) form.addControl(name, new FormControl(defaultValue, field.VALIDATORS)) | ||
61 | else form.addControl(name, new FormControl(defaultValue)) | ||
62 | } | ||
63 | } | ||
64 | |||
65 | } | ||
diff --git a/client/src/app/shared/forms/form-validators/index.ts b/client/src/app/shared/forms/form-validators/index.ts index 09ae86f8a..cf544b2a9 100644 --- a/client/src/app/shared/forms/form-validators/index.ts +++ b/client/src/app/shared/forms/form-validators/index.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | export * from './form-validator.service' | ||
1 | export * from './host' | 2 | export * from './host' |
2 | export * from './user' | 3 | export * from './user' |
3 | export * from './video-abuse' | 4 | export * from './video-abuse' |
diff --git a/client/src/app/shared/forms/form-validators/login.ts b/client/src/app/shared/forms/form-validators/login.ts new file mode 100644 index 000000000..f37f8d285 --- /dev/null +++ b/client/src/app/shared/forms/form-validators/login.ts | |||
@@ -0,0 +1,18 @@ | |||
1 | import { Validators } from '@angular/forms' | ||
2 | |||
3 | export const LOGIN_USERNAME = { | ||
4 | VALIDATORS: [ | ||
5 | Validators.required | ||
6 | ], | ||
7 | MESSAGES: { | ||
8 | 'required': 'Username is required.' | ||
9 | } | ||
10 | } | ||
11 | export const LOGIN_PASSWORD = { | ||
12 | VALIDATORS: [ | ||
13 | Validators.required | ||
14 | ], | ||
15 | MESSAGES: { | ||
16 | 'required': 'Password is required.' | ||
17 | } | ||
18 | } | ||
diff --git a/client/src/app/shared/forms/form-validators/reset-password.ts b/client/src/app/shared/forms/form-validators/reset-password.ts new file mode 100644 index 000000000..7dafdef9a --- /dev/null +++ b/client/src/app/shared/forms/form-validators/reset-password.ts | |||
@@ -0,0 +1,10 @@ | |||
1 | import { Validators } from '@angular/forms' | ||
2 | |||
3 | export const RESET_PASSWORD_CONFIRM = { | ||
4 | VALIDATORS: [ | ||
5 | Validators.required | ||
6 | ], | ||
7 | MESSAGES: { | ||
8 | 'required': 'Confirmation of the password is required.' | ||
9 | } | ||
10 | } | ||
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index fba099401..91d905ec7 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts | |||
@@ -34,6 +34,7 @@ import { VideoService } from './video/video.service' | |||
34 | import { AccountService } from '@app/shared/account/account.service' | 34 | import { AccountService } from '@app/shared/account/account.service' |
35 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' | 35 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' |
36 | import { I18n } from '@ngx-translate/i18n-polyfill' | 36 | import { I18n } from '@ngx-translate/i18n-polyfill' |
37 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' | ||
37 | 38 | ||
38 | @NgModule({ | 39 | @NgModule({ |
39 | imports: [ | 40 | imports: [ |
@@ -110,6 +111,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill' | |||
110 | AccountService, | 111 | AccountService, |
111 | MarkdownService, | 112 | MarkdownService, |
112 | VideoChannelService, | 113 | VideoChannelService, |
114 | FormValidatorService, | ||
113 | I18n | 115 | I18n |
114 | ] | 116 | ] |
115 | }) | 117 | }) |