-
Notifications
You must be signed in to change notification settings - Fork 87
Expand file tree
/
Copy pathngxerrors.directive.ts
More file actions
executable file
·121 lines (100 loc) · 3 KB
/
Copy pathngxerrors.directive.ts
File metadata and controls
executable file
·121 lines (100 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { Directive, Input, OnChanges, OnDestroy, AfterViewInit, ChangeDetectorRef } from '@angular/core';
import { FormGroupDirective, AbstractControl } from '@angular/forms';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { ErrorDetails, ErrorOptions } from './ngxerrors';
import { toArray } from './utils/toArray';
@Directive({
selector: '[ngxErrors]',
exportAs: 'ngxErrors'
})
export class NgxErrorsDirective implements OnChanges, OnDestroy, AfterViewInit {
@Input('ngxErrors')
controlName: string;
subject = new BehaviorSubject<ErrorDetails>(null);
control: AbstractControl;
ready: boolean = false;
constructor(
public form: FormGroupDirective,
private changeDetectorRef: ChangeDetectorRef
) { }
get errors() {
if (!this.ready) return;
if (this.control) {
return this.control.errors;
}
return this.form.errors;
}
get hasErrors() {
return !!this.errors;
}
hasError(name: string, conditions: ErrorOptions): boolean {
return this.checkPropState('invalid', name, conditions);
}
isValid(name: string, conditions: ErrorOptions): boolean {
return this.checkPropState('valid', name, conditions);
}
getError(name: string) {
if (!this.ready) return;
if (this.control) {
return this.control.getError(name);
}
return this.form.getError(name);
}
private checkPropState(prop: string, name: string, conditions: ErrorOptions): boolean {
if (!this.ready) return;
const propsState = (
!conditions || toArray(conditions).every(
(condition: string) =>
this.control ? this.control[condition] : this.form[condition]
)
);
if (name.charAt(0) === '*') {
if (this.control) {
return this.control[prop] && propsState;
}
return this.form[prop] && propsState;
}
if (this.control) {
return (
prop === 'valid' ? !this.control.hasError(name) : this.control.hasError(name) && propsState
);
}
return (
prop === 'valid' ? !this.form.hasError(name) : this.form.hasError(name) && propsState
);
}
private checkStatus() {
const control = this.control;
const form = this.form;
const errors = control ? control.errors : form.errors;
this.ready = true;
if (!errors) return;
for (const errorName in errors) {
if (this.control) {
this.subject.next({ control, errorName });
} else {
this.subject.next({ form, errorName });
// why does this seem necessary? I don't understand
this.changeDetectorRef.detectChanges();
}
}
}
ngOnChanges() {
if (this.controlName) {
this.control = this.form.control.get(this.controlName);
}
}
ngAfterViewInit() {
setTimeout(() => {
this.checkStatus();
if (this.control) {
this.control.statusChanges.subscribe(this.checkStatus.bind(this));
} else {
this.form.statusChanges.subscribe(this.checkStatus.bind(this));
}
});
}
ngOnDestroy() {
this.subject.unsubscribe();
}
}