1
1
part of angular.directive;
2
2
3
+ /**
4
+ * The NgControl class is a super-class for handling info and error states between
5
+ * inner controls and models. NgControl will automatically apply the associated CSS
6
+ * classes for the error and info states that are applied as well as status flags.
7
+ * NgControl is used with the form and fieldset as well as all other directives that
8
+ * are used for user input with NgModel.
9
+ */
3
10
abstract class NgControl implements NgAttachAware , NgDetachAware {
4
11
static const NG_VALID = "ng-valid" ;
5
12
static const NG_INVALID = "ng-invalid" ;
@@ -15,12 +22,21 @@ abstract class NgControl implements NgAttachAware, NgDetachAware {
15
22
16
23
final NgControl _parentControl;
17
24
final NgAnimate _animate;
18
- NgElement _element;
25
+ final NgElement _element;
19
26
20
27
final _controls = new List <NgControl >();
21
28
final _controlByName = new Map <String , List <NgControl >>();
22
29
30
+ /**
31
+ * The list of errors present on the control represented by an error name and
32
+ * an inner control instance.
33
+ */
23
34
final errorStates = new Map <String , Set <NgControl >>();
35
+
36
+ /**
37
+ * The list of info messages present on the control represented by an state name and
38
+ * an inner control instance.
39
+ */
24
40
final infoStates = new Map <String , Set <NgControl >>();
25
41
26
42
NgControl (NgElement this ._element, Injector injector,
@@ -36,13 +52,16 @@ abstract class NgControl implements NgAttachAware, NgDetachAware {
36
52
_parentControl.removeControl (this );
37
53
}
38
54
39
- reset () {
55
+ /**
56
+ * Resets the form and inner models to their pristine state.
57
+ */
58
+ void reset () {
40
59
_controls.forEach ((control) {
41
60
control.reset ();
42
61
});
43
62
}
44
63
45
- onSubmit (bool valid) {
64
+ void onSubmit (bool valid) {
46
65
if (valid) {
47
66
_submit_valid = true ;
48
67
element..addClass (NG_SUBMIT_VALID )..removeClass (NG_SUBMIT_INVALID );
@@ -55,34 +74,69 @@ abstract class NgControl implements NgAttachAware, NgDetachAware {
55
74
});
56
75
}
57
76
58
- get parentControl => _parentControl;
77
+ NgControl get parentControl => _parentControl;
59
78
60
- get submitted => _submit_valid != null ;
61
- get valid_submit => _submit_valid == true ;
62
- get invalid_submit => _submit_valid == false ;
79
+ /**
80
+ * Whether or not the form has been submitted yet.
81
+ */
82
+ bool get submitted => _submit_valid != null ;
83
+
84
+ /**
85
+ * Whether or not the form was valid when last submitted.
86
+ */
87
+ bool get valid_submit => _submit_valid == true ;
88
+
89
+ /**
90
+ * Whether or not the form was invalid when last submitted.
91
+ */
92
+ bool get invalid_submit => _submit_valid == false ;
63
93
64
- get name => _name;
94
+ String get name => _name;
65
95
set name (value) {
66
96
_name = value;
67
97
}
68
98
69
- get element => _element;
99
+ /**
100
+ * Whether or not the form was invalid when last submitted.
101
+ */
102
+ NgElement get element => _element;
70
103
71
- get valid => ! invalid;
72
- get invalid => errorStates.isNotEmpty;
104
+ /**
105
+ * A control is considered valid if all inner models are valid.
106
+ */
107
+ bool get valid => ! invalid;
73
108
74
- get pristine => ! dirty;
75
- get dirty => infoStates.containsKey (NG_DIRTY );
109
+ /**
110
+ * A control is considered invalid if any inner models are invalid.
111
+ */
112
+ bool get invalid => errorStates.isNotEmpty;
76
113
77
- get untouched => ! touched;
78
- get touched => infoStates.containsKey (NG_TOUCHED );
114
+ /**
115
+ * Whether or not the control's or model's data has not been changed.
116
+ */
117
+ bool get pristine => ! dirty;
118
+
119
+ /**
120
+ * Whether or not the control's or model's data has been changed.
121
+ */
122
+ bool get dirty => infoStates.containsKey (NG_DIRTY );
123
+
124
+ /**
125
+ * Whether or not the control/model has not been interacted with by the user.
126
+ */
127
+ bool get untouched => ! touched;
128
+
129
+ /**
130
+ * Whether or not the control/model has been interacted with by the user.
131
+ */
132
+ bool get touched => infoStates.containsKey (NG_TOUCHED );
79
133
80
134
/**
81
135
* Registers a form control into the form for validation.
82
136
*
83
- * * [control] - The form control which will be registered (see [ngControl ] ).
137
+ * * [control] - The form control which will be registered (see [NgControl ] ).
84
138
*/
85
- addControl (NgControl control) {
139
+ void addControl (NgControl control) {
86
140
_controls.add (control);
87
141
if (control.name != null ) {
88
142
_controlByName.putIfAbsent (control.name, () => new List <NgControl >()).add (control);
@@ -93,10 +147,9 @@ abstract class NgControl implements NgAttachAware, NgDetachAware {
93
147
* De-registers a form control from the list of controls associated with the
94
148
* form.
95
149
*
96
- * * [control] - The form control which will be de-registered (see
97
- * [ngControl] ).
150
+ * * [control] - The form control which will be de-registered (see [NgControl] ).
98
151
*/
99
- removeControl (NgControl control) {
152
+ void removeControl (NgControl control) {
100
153
_controls.remove (control);
101
154
String key = control.name;
102
155
if (key != null && _controlByName.containsKey (key)) {
@@ -107,7 +160,12 @@ abstract class NgControl implements NgAttachAware, NgDetachAware {
107
160
}
108
161
}
109
162
110
- removeStates (NgControl control) {
163
+ /**
164
+ * Clears all the info and error states that are associated with the control.
165
+ *
166
+ * * [control] - The form control which will be cleared of all state (see [NgControl] ).
167
+ */
168
+ void removeStates (NgControl control) {
111
169
bool hasRemovals = false ;
112
170
errorStates.keys.toList ().forEach ((state) {
113
171
Set matchingControls = errorStates[state];
@@ -133,41 +191,48 @@ abstract class NgControl implements NgAttachAware, NgDetachAware {
133
191
}
134
192
135
193
/**
136
- * Sets the validity status of the given control/errorType pair within
137
- * the list of controls registered on the form. Depending on the validation
138
- * state of the existing controls, this will either change valid to true
139
- * or invalid to true depending on if all controls are valid or if one
140
- * or more of them is invalid.
194
+ * Whether or not the control contains the given error.
141
195
*
142
- * * [control] - The registered control object (see [ngControl] ).
143
- * * [errorType] - The error associated with the control (e.g. required, url,
144
- * number, etc...).
145
- * * [isValid] - Whether the given error is valid or not (false would mean the
146
- * error is real).
196
+ * * [errorName] - The name of the error (e.g. ng-required, ng-pattern, etc...)
147
197
*/
148
- bool hasErrorState (String key ) => errorStates.containsKey (key );
198
+ bool hasErrorState (String errorName ) => errorStates.containsKey (errorName );
149
199
150
- addErrorState (NgControl control, String state) {
151
- element..addClass (state + '-invalid' )..removeClass (state + '-valid' );
152
- errorStates.putIfAbsent (state, () => new Set ()).add (control);
153
- _parentControl.addErrorState (this , state);
200
+ /**
201
+ * Adds the given childControl/errorName to the list of errors present on the control. Once
202
+ * added all associated parent controls will be registered with the error as well.
203
+ *
204
+ * * [childControl] - The child control that contains the error.
205
+ * * [errorName] - The name of the given error (e.g. ng-required, ng-pattern, etc...).
206
+ */
207
+ void addErrorState (NgControl childControl, String errorName) {
208
+ element..addClass (errorName + '-invalid' )..removeClass (errorName + '-valid' );
209
+ errorStates.putIfAbsent (errorName, () => new Set ()).add (childControl);
210
+ _parentControl.addErrorState (this , errorName);
154
211
}
155
212
156
- removeErrorState (NgControl control, String state) {
157
- if (! errorStates.containsKey (state)) return ;
213
+ /**
214
+ * Removes the given childControl/errorName from the list of errors present on the control. Once
215
+ * removed the control will update any parent controls depending if error is not present on
216
+ * any other inner controls and or models.
217
+ *
218
+ * * [childControl] - The child control that contains the error.
219
+ * * [errorName] - The name of the given error (e.g. ng-required, ng-pattern, etc...).
220
+ */
221
+ void removeErrorState (NgControl childControl, String errorName) {
222
+ if (! errorStates.containsKey (errorName)) return ;
158
223
159
- bool hasState = _controls.isEmpty ||
160
- _controls.every ((control ) {
161
- return ! control .hasErrorState (state );
224
+ bool hasError = _controls.isEmpty ||
225
+ _controls.every ((childControl ) {
226
+ return ! childControl .hasErrorState (errorName );
162
227
});
163
- if (hasState ) {
164
- errorStates.remove (state );
165
- _parentControl.removeErrorState (this , state );
166
- element..removeClass (state + '-invalid' )..addClass (state + '-valid' );
228
+ if (hasError ) {
229
+ errorStates.remove (errorName );
230
+ _parentControl.removeErrorState (this , errorName );
231
+ element..removeClass (errorName + '-invalid' )..addClass (errorName + '-valid' );
167
232
}
168
233
}
169
234
170
- _getOppositeInfoState (String state) {
235
+ String _getOppositeInfoState (String state) {
171
236
switch (state) {
172
237
case NG_DIRTY :
173
238
return NG_PRISTINE ;
@@ -179,35 +244,51 @@ abstract class NgControl implements NgAttachAware, NgDetachAware {
179
244
}
180
245
}
181
246
182
- addInfoState (NgControl control, String state) {
183
- String oppositeState = _getOppositeInfoState (state);
247
+ /**
248
+ * Registers a non-error state on the control with the given childControl/stateName data. Once
249
+ * added the control will also add the same data to any associated parent controls.
250
+ *
251
+ * * [childControl] - The child control that contains the error.
252
+ * * [stateName] - The name of the given error (e.g. ng-required, ng-pattern, etc...).
253
+ */
254
+ void addInfoState (NgControl childControl, String stateName) {
255
+ String oppositeState = _getOppositeInfoState (stateName);
184
256
if (oppositeState != null ) {
185
257
element.removeClass (oppositeState);
186
258
}
187
- element.addClass (state );
188
- infoStates.putIfAbsent (state , () => new Set ()).add (control );
189
- _parentControl.addInfoState (this , state );
259
+ element.addClass (stateName );
260
+ infoStates.putIfAbsent (stateName , () => new Set ()).add (childControl );
261
+ _parentControl.addInfoState (this , stateName );
190
262
}
191
263
192
- removeInfoState (NgControl control, String state) {
193
- String oppositeState = _getOppositeInfoState (state);
194
- if (infoStates.containsKey (state)) {
264
+ /**
265
+ * De-registers the provided state on the control with the given childControl. The state
266
+ * will be fully removed from the control if all of the inner controls/models also do not
267
+ * contain the state. If so then the state will also be attempted to be removed from the
268
+ * associated parent controls.
269
+ *
270
+ * * [childControl] - The child control that contains the error.
271
+ * * [stateName] - The name of the given error (e.g. ng-required, ng-pattern, etc...).
272
+ */
273
+ void removeInfoState (NgControl childControl, String stateName) {
274
+ String oppositeState = _getOppositeInfoState (stateName);
275
+ if (infoStates.containsKey (stateName)) {
195
276
bool hasState = _controls.isEmpty ||
196
- _controls.every ((control ) {
197
- return ! control .infoStates.containsKey (state );
277
+ _controls.every ((childControl ) {
278
+ return ! childControl .infoStates.containsKey (stateName );
198
279
});
199
280
if (hasState) {
200
281
if (oppositeState != null ) {
201
282
element.addClass (oppositeState);
202
283
}
203
- element.removeClass (state );
204
- infoStates.remove (state );
205
- _parentControl.removeInfoState (this , state );
284
+ element.removeClass (stateName );
285
+ infoStates.remove (stateName );
286
+ _parentControl.removeInfoState (this , stateName );
206
287
}
207
288
} else if (oppositeState != null ) {
208
289
NgControl parent = this ;
209
290
do {
210
- parent.element..addClass (oppositeState)..removeClass (state );
291
+ parent.element..addClass (oppositeState)..removeClass (stateName );
211
292
parent = parent.parentControl;
212
293
}
213
294
while (parent != null && ! (parent is NgNullControl ));
0 commit comments