aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/shared')
-rw-r--r--client/src/app/shared/form-validators/form-validator.model.ts4
-rw-r--r--client/src/app/shared/shared-forms/form-reactive.ts40
-rw-r--r--client/src/app/shared/shared-forms/form-validator.service.ts16
-rw-r--r--client/src/app/shared/shared-user-subscription/remote-subscribe.component.ts2
4 files changed, 44 insertions, 18 deletions
diff --git a/client/src/app/shared/form-validators/form-validator.model.ts b/client/src/app/shared/form-validators/form-validator.model.ts
index 6f2472ccd..31c253b9b 100644
--- a/client/src/app/shared/form-validators/form-validator.model.ts
+++ b/client/src/app/shared/form-validators/form-validator.model.ts
@@ -1,7 +1,9 @@
1import { ValidatorFn } from '@angular/forms' 1import { AsyncValidatorFn, ValidatorFn } from '@angular/forms'
2 2
3export type BuildFormValidator = { 3export type BuildFormValidator = {
4 VALIDATORS: ValidatorFn[] 4 VALIDATORS: ValidatorFn[]
5 ASYNC_VALIDATORS?: AsyncValidatorFn[]
6
5 MESSAGES: { [ name: string ]: string } 7 MESSAGES: { [ name: string ]: string }
6} 8}
7 9
diff --git a/client/src/app/shared/shared-forms/form-reactive.ts b/client/src/app/shared/shared-forms/form-reactive.ts
index 30b59c141..07a12c6f6 100644
--- a/client/src/app/shared/shared-forms/form-reactive.ts
+++ b/client/src/app/shared/shared-forms/form-reactive.ts
@@ -1,4 +1,6 @@
1
1import { FormGroup } from '@angular/forms' 2import { FormGroup } from '@angular/forms'
3import { wait } from '@root-helpers/utils'
2import { BuildFormArgument, BuildFormDefaultValues } from '../form-validators/form-validator.model' 4import { BuildFormArgument, BuildFormDefaultValues } from '../form-validators/form-validator.model'
3import { FormValidatorService } from './form-validator.service' 5import { FormValidatorService } from './form-validator.service'
4 6
@@ -22,30 +24,42 @@ export abstract class FormReactive {
22 this.formErrors = formErrors 24 this.formErrors = formErrors
23 this.validationMessages = validationMessages 25 this.validationMessages = validationMessages
24 26
25 this.form.valueChanges.subscribe(() => this.onValueChanged(this.form, this.formErrors, this.validationMessages, false)) 27 this.form.statusChanges.subscribe(async status => {
28 // FIXME: remove when https://github.com/angular/angular/issues/41519 is fixed
29 await this.waitPendingCheck()
30
31 this.onStatusChanged(this.form, this.formErrors, this.validationMessages)
32 })
26 } 33 }
27 34
28 protected forceCheck () { 35 protected async waitPendingCheck () {
29 return this.onValueChanged(this.form, this.formErrors, this.validationMessages, true) 36 if (this.form.status !== 'PENDING') return
37
38 // FIXME: the following line does not work: https://github.com/angular/angular/issues/41519
39 // return firstValueFrom(this.form.statusChanges.pipe(filter(status => status !== 'PENDING')))
40 // So we have to fallback to active wait :/
41
42 do {
43 await wait(10)
44 } while (this.form.status === 'PENDING')
30 } 45 }
31 46
32 protected check () { 47 protected forceCheck () {
33 return this.onValueChanged(this.form, this.formErrors, this.validationMessages, false) 48 this.onStatusChanged(this.form, this.formErrors, this.validationMessages, false)
34 } 49 }
35 50
36 private onValueChanged ( 51 private onStatusChanged (
37 form: FormGroup, 52 form: FormGroup,
38 formErrors: FormReactiveErrors, 53 formErrors: FormReactiveErrors,
39 validationMessages: FormReactiveValidationMessages, 54 validationMessages: FormReactiveValidationMessages,
40 forceCheck = false 55 onlyDirty = true
41 ) { 56 ) {
42 for (const field of Object.keys(formErrors)) { 57 for (const field of Object.keys(formErrors)) {
43 if (formErrors[field] && typeof formErrors[field] === 'object') { 58 if (formErrors[field] && typeof formErrors[field] === 'object') {
44 this.onValueChanged( 59 this.onStatusChanged(
45 form.controls[field] as FormGroup, 60 form.controls[field] as FormGroup,
46 formErrors[field] as FormReactiveErrors, 61 formErrors[field] as FormReactiveErrors,
47 validationMessages[field] as FormReactiveValidationMessages, 62 validationMessages[field] as FormReactiveValidationMessages
48 forceCheck
49 ) 63 )
50 continue 64 continue
51 } 65 }
@@ -56,8 +70,7 @@ export abstract class FormReactive {
56 70
57 if (control.dirty) this.formChanged = true 71 if (control.dirty) this.formChanged = true
58 72
59 if (forceCheck) control.updateValueAndValidity({ emitEvent: false }) 73 if (!control || (onlyDirty && !control.dirty) || !control.enabled || !control.errors) continue
60 if (!control || !control.dirty || !control.enabled || control.valid) continue
61 74
62 const staticMessages = validationMessages[field] 75 const staticMessages = validationMessages[field]
63 for (const key of Object.keys(control.errors)) { 76 for (const key of Object.keys(control.errors)) {
@@ -65,11 +78,10 @@ export abstract class FormReactive {
65 78
66 // Try to find error message in static validation messages first 79 // Try to find error message in static validation messages first
67 // Then check if the validator returns a string that is the error 80 // Then check if the validator returns a string that is the error
68 if (typeof formErrorValue === 'boolean') formErrors[field] += staticMessages[key] + ' ' 81 if (staticMessages[key]) formErrors[field] += staticMessages[key] + ' '
69 else if (typeof formErrorValue === 'string') formErrors[field] += control.errors[key] 82 else if (typeof formErrorValue === 'string') formErrors[field] += control.errors[key]
70 else throw new Error('Form error value of ' + field + ' is invalid') 83 else throw new Error('Form error value of ' + field + ' is invalid')
71 } 84 }
72 } 85 }
73 } 86 }
74
75} 87}
diff --git a/client/src/app/shared/shared-forms/form-validator.service.ts b/client/src/app/shared/shared-forms/form-validator.service.ts
index 055fbb2d9..0fe50ac9b 100644
--- a/client/src/app/shared/shared-forms/form-validator.service.ts
+++ b/client/src/app/shared/shared-forms/form-validator.service.ts
@@ -1,5 +1,5 @@
1import { Injectable } from '@angular/core' 1import { Injectable } from '@angular/core'
2import { FormBuilder, FormControl, FormGroup, ValidatorFn } from '@angular/forms' 2import { AsyncValidatorFn, FormArray, FormBuilder, FormControl, FormGroup, ValidatorFn } from '@angular/forms'
3import { BuildFormArgument, BuildFormDefaultValues } from '../form-validators/form-validator.model' 3import { BuildFormArgument, BuildFormDefaultValues } from '../form-validators/form-validator.model'
4import { FormReactiveErrors, FormReactiveValidationMessages } from './form-reactive' 4import { FormReactiveErrors, FormReactiveValidationMessages } from './form-reactive'
5 5
@@ -68,11 +68,23 @@ export class FormValidatorService {
68 68
69 form.addControl( 69 form.addControl(
70 name, 70 name,
71 new FormControl(defaultValue, field?.VALIDATORS as ValidatorFn[]) 71 new FormControl(defaultValue, field?.VALIDATORS as ValidatorFn[], field?.ASYNC_VALIDATORS as AsyncValidatorFn[])
72 ) 72 )
73 } 73 }
74 } 74 }
75 75
76 updateTreeValidity (group: FormGroup | FormArray): void {
77 for (const key of Object.keys(group.controls)) {
78 const abstractControl = group.controls[key] as FormControl
79
80 if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) {
81 this.updateTreeValidity(abstractControl)
82 } else {
83 abstractControl.updateValueAndValidity({ emitEvent: false })
84 }
85 }
86 }
87
76 private isRecursiveField (field: any) { 88 private isRecursiveField (field: any) {
77 return field && typeof field === 'object' && !field.MESSAGES && !field.VALIDATORS 89 return field && typeof field === 'object' && !field.MESSAGES && !field.VALIDATORS
78 } 90 }
diff --git a/client/src/app/shared/shared-user-subscription/remote-subscribe.component.ts b/client/src/app/shared/shared-user-subscription/remote-subscribe.component.ts
index a951134eb..369692715 100644
--- a/client/src/app/shared/shared-user-subscription/remote-subscribe.component.ts
+++ b/client/src/app/shared/shared-user-subscription/remote-subscribe.component.ts
@@ -27,7 +27,7 @@ export class RemoteSubscribeComponent extends FormReactive implements OnInit {
27 } 27 }
28 28
29 onValidKey () { 29 onValidKey () {
30 this.check() 30 this.forceCheck()
31 if (!this.form.valid) return 31 if (!this.form.valid) return
32 32
33 this.formValidated() 33 this.formValidated()