-
Notifications
You must be signed in to change notification settings - Fork 25.6k
/
ng_control_status.ts
145 lines (129 loc) · 3.86 KB
/
ng_control_status.ts
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Directive, Optional, Self, ɵWritable as Writable} from '@angular/core';
import {AbstractControlDirective} from './abstract_control_directive';
import {ControlContainer} from './control_container';
import {NgControl} from './ng_control';
import {type NgForm} from './ng_form';
import {type FormGroupDirective} from './reactive_directives/form_group_directive';
// DO NOT REFACTOR!
// Each status is represented by a separate function to make sure that
// advanced Closure Compiler optimizations related to property renaming
// can work correctly.
export class AbstractControlStatus {
private _cd: AbstractControlDirective | null;
constructor(cd: AbstractControlDirective | null) {
this._cd = cd;
}
protected get isTouched() {
// track the touched signal
this._cd?.control?._touched?.();
return !!this._cd?.control?.touched;
}
protected get isUntouched() {
return !!this._cd?.control?.untouched;
}
protected get isPristine() {
// track the pristine signal
this._cd?.control?._pristine?.();
return !!this._cd?.control?.pristine;
}
protected get isDirty() {
// pristine signal already tracked above
return !!this._cd?.control?.dirty;
}
protected get isValid() {
// track the status signal
this._cd?.control?._status?.();
return !!this._cd?.control?.valid;
}
protected get isInvalid() {
// status signal already tracked above
return !!this._cd?.control?.invalid;
}
protected get isPending() {
// status signal already tracked above
return !!this._cd?.control?.pending;
}
protected get isSubmitted() {
// track the submitted signal
(this._cd as Writable<NgForm | FormGroupDirective> | null)?._submitted?.();
// We check for the `submitted` field from `NgForm` and `FormGroupDirective` classes, but
// we avoid instanceof checks to prevent non-tree-shakable references to those types.
return !!(this._cd as Writable<NgForm | FormGroupDirective> | null)?.submitted;
}
}
export const ngControlStatusHost = {
'[class.ng-untouched]': 'isUntouched',
'[class.ng-touched]': 'isTouched',
'[class.ng-pristine]': 'isPristine',
'[class.ng-dirty]': 'isDirty',
'[class.ng-valid]': 'isValid',
'[class.ng-invalid]': 'isInvalid',
'[class.ng-pending]': 'isPending',
};
export const ngGroupStatusHost = {
...ngControlStatusHost,
'[class.ng-submitted]': 'isSubmitted',
};
/**
* @description
* Directive automatically applied to Angular form controls that sets CSS classes
* based on control status.
*
* @usageNotes
*
* ### CSS classes applied
*
* The following classes are applied as the properties become true:
*
* * ng-valid
* * ng-invalid
* * ng-pending
* * ng-pristine
* * ng-dirty
* * ng-untouched
* * ng-touched
*
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
* @publicApi
*/
@Directive({
selector: '[formControlName],[ngModel],[formControl]',
host: ngControlStatusHost,
standalone: false,
})
export class NgControlStatus extends AbstractControlStatus {
constructor(@Self() cd: NgControl) {
super(cd);
}
}
/**
* @description
* Directive automatically applied to Angular form groups that sets CSS classes
* based on control status (valid/invalid/dirty/etc). On groups, this includes the additional
* class ng-submitted.
*
* @see {@link NgControlStatus}
*
* @ngModule ReactiveFormsModule
* @ngModule FormsModule
* @publicApi
*/
@Directive({
selector:
'[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]',
host: ngGroupStatusHost,
standalone: false,
})
export class NgControlStatusGroup extends AbstractControlStatus {
constructor(@Optional() @Self() cd: ControlContainer) {
super(cd);
}
}