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 ;
@@ -181,35 +246,51 @@ abstract class NgControl implements NgAttachAware, NgDetachAware {
181
246
}
182
247
}
183
248
184
- addInfoState (NgControl control, String state) {
185
- String oppositeState = _getOppositeInfoState (state);
249
+ /**
250
+ * Registers a non-error state on the control with the given childControl/stateName data. Once
251
+ * added the control will also add the same data to any associated parent controls.
252
+ *
253
+ * * [childControl] - The child control that contains the error.
254
+ * * [stateName] - The name of the given error (e.g. ng-required, ng-pattern, etc...).
255
+ */
256
+ void addInfoState (NgControl childControl, String stateName) {
257
+ String oppositeState = _getOppositeInfoState (stateName);
186
258
if (oppositeState != null ) {
187
259
element.removeClass (oppositeState);
188
260
}
189
- element.addClass (state );
190
- infoStates.putIfAbsent (state , () => new Set ()).add (control );
191
- _parentControl.addInfoState (this , state );
261
+ element.addClass (stateName );
262
+ infoStates.putIfAbsent (stateName , () => new Set ()).add (childControl );
263
+ _parentControl.addInfoState (this , stateName );
192
264
}
193
265
194
- removeInfoState (NgControl control, String state) {
195
- String oppositeState = _getOppositeInfoState (state);
196
- if (infoStates.containsKey (state)) {
266
+ /**
267
+ * De-registers the provided state on the control with the given childControl. The state
268
+ * will be fully removed from the control if all of the inner controls/models also do not
269
+ * contain the state. If so then the state will also be attempted to be removed from the
270
+ * associated parent controls.
271
+ *
272
+ * * [childControl] - The child control that contains the error.
273
+ * * [stateName] - The name of the given error (e.g. ng-required, ng-pattern, etc...).
274
+ */
275
+ void removeInfoState (NgControl childControl, String stateName) {
276
+ String oppositeState = _getOppositeInfoState (stateName);
277
+ if (infoStates.containsKey (stateName)) {
197
278
bool hasState = _controls.isEmpty ||
198
- _controls.every ((control ) {
199
- return ! control .infoStates.containsKey (state );
279
+ _controls.every ((childControl ) {
280
+ return ! childControl .infoStates.containsKey (stateName );
200
281
});
201
282
if (hasState) {
202
283
if (oppositeState != null ) {
203
284
element.addClass (oppositeState);
204
285
}
205
- element.removeClass (state );
206
- infoStates.remove (state );
207
- _parentControl.removeInfoState (this , state );
286
+ element.removeClass (stateName );
287
+ infoStates.remove (stateName );
288
+ _parentControl.removeInfoState (this , stateName );
208
289
}
209
290
} else if (oppositeState != null ) {
210
291
NgControl parent = this ;
211
292
do {
212
- parent.element..addClass (oppositeState)..removeClass (state );
293
+ parent.element..addClass (oppositeState)..removeClass (stateName );
213
294
parent = parent.parentControl;
214
295
}
215
296
while (parent != null && ! (parent is NgNullControl ));
0 commit comments