OLD | NEW |
1 part of angular.directive; | 1 part of angular.directive; |
2 | 2 |
3 abstract class NgValidatable { | 3 /** |
| 4 * NgValidator is the class interface for performing validations for an NgModel
instance. |
| 5 */ |
| 6 abstract class NgValidator { |
| 7 /** |
| 8 * The name of the validator. This name will be used as the key value within t
he |
| 9 * model.errorStates map and it will also be applied as a CSS class on the ass
ociated |
| 10 * DOM element. Therefore, as a best practice, please do not include spaces fo
r the validator |
| 11 * name since it may cause issues with the CSS naming. |
| 12 */ |
4 String get name; | 13 String get name; |
5 bool isValid(value); | 14 bool isValid(modelValue); |
6 } | 15 } |
7 | 16 |
8 /** | 17 /** |
9 * Validates the model depending if required or ng-required is present on the el
ement. | 18 * Validates the model depending if required or ng-required is present on the el
ement. |
10 */ | 19 */ |
11 @NgDirective( | 20 @Decorator( |
12 selector: '[ng-model][required]') | 21 selector: '[ng-model][required]') |
13 @NgDirective( | 22 @Decorator( |
14 selector: '[ng-model][ng-required]', | 23 selector: '[ng-model][ng-required]', |
15 map: const {'ng-required': '=>required'}) | 24 map: const {'ng-required': '=>required'}) |
16 class NgModelRequiredValidator implements NgValidatable { | 25 class NgModelRequiredValidator implements NgValidator { |
| 26 |
| 27 final String name = 'ng-required'; |
17 bool _required = true; | 28 bool _required = true; |
| 29 final NgModel _ngModel; |
18 | 30 |
19 String get name => 'required'; | 31 NgModelRequiredValidator(NgModel this._ngModel) { |
20 | 32 _ngModel.addValidator(this); |
21 NgModelRequiredValidator(NgModel ngModel) { | |
22 ngModel.addValidator(this); | |
23 } | 33 } |
24 | 34 |
25 bool isValid(value) { | 35 bool isValid(modelValue) { |
26 // Any element which isn't required is always valid. | 36 // Any element which isn't required is always valid. |
27 if (!_required) return true; | 37 if (!_required) return true; |
28 // Null is not a value, therefore not valid. | 38 // Null is not a value, therefore not valid. |
29 if (value == null) return false; | 39 if (modelValue == null) return false; |
30 // Empty lists and/or strings are not valid. | 40 // Empty lists and/or strings are not valid. |
31 // NOTE: This is an excellent use case for structural typing. | 41 // NOTE: This is an excellent use case for structural typing. |
32 // We really want anything object that has a 'isEmpty' property. | 42 // We really want anything object that has a 'isEmpty' property. |
33 return !((value is List || value is String) && value.isEmpty); | 43 return !((modelValue is List || modelValue is String) && modelValue.isEmpty)
; |
34 } | 44 } |
35 | 45 |
36 set required(value) { | 46 set required(value) { |
37 _required = value == null ? false : value; | 47 _required = value == null ? false : value; |
| 48 _ngModel.validateLater(); |
38 } | 49 } |
39 } | 50 } |
40 | 51 |
41 /** | 52 /** |
42 * Validates the model to see if its contents match a valid URL pattern. | 53 * Validates the model to see if its contents match a valid URL pattern. |
43 */ | 54 */ |
44 @NgDirective(selector: 'input[type=url][ng-model]') | 55 @Decorator(selector: 'input[type=url][ng-model]') |
45 class NgModelUrlValidator implements NgValidatable { | 56 class NgModelUrlValidator implements NgValidator { |
46 static final URL_REGEXP = new RegExp( | 57 static final URL_REGEXP = new RegExp( |
47 r'^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?' + | 58 r'^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?' + |
48 r'(\/|\/([\w#!:.?+=&%@!\-\/]))?$'); | 59 r'(\/|\/([\w#!:.?+=&%@!\-\/]))?$'); |
49 | 60 |
50 String get name => 'url'; | 61 final String name = 'ng-url'; |
51 | 62 |
52 NgModelUrlValidator(NgModel ngModel) { | 63 NgModelUrlValidator(NgModel ngModel) { |
53 ngModel.addValidator(this); | 64 ngModel.addValidator(this); |
54 } | 65 } |
55 | 66 |
56 bool isValid(value) => | 67 bool isValid(modelValue) => |
57 value == null || value.isEmpty || URL_REGEXP.hasMatch(value); | 68 modelValue == null || modelValue.isEmpty || URL_REGEXP.hasMatch(modelValue
); |
58 } | 69 } |
59 | 70 |
60 /** | 71 /** |
61 * Validates the model to see if its contents match a valid email pattern. | 72 * Validates the model to see if its contents match a valid email pattern. |
62 */ | 73 */ |
63 @NgDirective(selector: 'input[type=email][ng-model]') | 74 @Decorator(selector: 'input[type=email][ng-model]') |
64 class NgModelEmailValidator implements NgValidatable { | 75 class NgModelEmailValidator implements NgValidator { |
65 static final EMAIL_REGEXP = new RegExp( | 76 static final EMAIL_REGEXP = new RegExp( |
66 r'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$'); | 77 r'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$'); |
67 | 78 |
68 String get name => 'email'; | 79 final String name = 'ng-email'; |
69 | 80 |
70 NgModelEmailValidator(NgModel ngModel) { | 81 NgModelEmailValidator(NgModel ngModel) { |
71 ngModel.addValidator(this); | 82 ngModel.addValidator(this); |
72 } | 83 } |
73 | 84 |
74 bool isValid(value) => | 85 bool isValid(modelValue) => |
75 value == null || value.isEmpty || EMAIL_REGEXP.hasMatch(value); | 86 modelValue == null || modelValue.isEmpty || EMAIL_REGEXP.hasMatch(modelVal
ue); |
76 } | 87 } |
77 | 88 |
78 /** | 89 /** |
79 * Validates the model to see if its contents match a valid number. | 90 * Validates the model to see if its contents match a valid number. |
80 */ | 91 */ |
81 @NgDirective(selector: 'input[type=number][ng-model]') | 92 @Decorator(selector: 'input[type=number][ng-model]') |
82 class NgModelNumberValidator implements NgValidatable { | 93 @Decorator(selector: 'input[type=range][ng-model]') |
83 String get name => 'number'; | 94 class NgModelNumberValidator implements NgValidator { |
| 95 |
| 96 final String name = 'ng-number'; |
84 | 97 |
85 NgModelNumberValidator(NgModel ngModel) { | 98 NgModelNumberValidator(NgModel ngModel) { |
86 ngModel.addValidator(this); | 99 ngModel.addValidator(this); |
87 } | 100 } |
88 | 101 |
89 bool isValid(value) { | 102 bool isValid(modelValue) { |
90 if (value != null) { | 103 if (modelValue != null) { |
91 try { | 104 try { |
92 num val = double.parse(value.toString()); | 105 num val = double.parse(modelValue.toString()); |
| 106 if (val.isNaN) { |
| 107 return false; |
| 108 } |
93 } catch(exception, stackTrace) { | 109 } catch(exception, stackTrace) { |
94 return false; | 110 return false; |
95 } | 111 } |
96 } | 112 } |
97 return true; | 113 return true; |
98 } | 114 } |
99 } | 115 } |
100 | 116 |
101 /** | 117 /** |
| 118 * Validates the model to see if the numeric value than or equal to the max valu
e. |
| 119 */ |
| 120 @Decorator(selector: 'input[type=number][ng-model][max]') |
| 121 @Decorator(selector: 'input[type=range][ng-model][max]') |
| 122 @Decorator( |
| 123 selector: 'input[type=number][ng-model][ng-max]', |
| 124 map: const {'ng-max': '=>max'}) |
| 125 @Decorator( |
| 126 selector: 'input[type=range][ng-model][ng-max]', |
| 127 map: const {'ng-max': '=>max'}) |
| 128 class NgModelMaxNumberValidator implements NgValidator { |
| 129 |
| 130 final String name = 'ng-max'; |
| 131 double _max; |
| 132 final NgModel _ngModel; |
| 133 |
| 134 NgModelMaxNumberValidator(NgModel this._ngModel) { |
| 135 _ngModel.addValidator(this); |
| 136 } |
| 137 |
| 138 @NgAttr('max') |
| 139 get max => _max; |
| 140 set max(value) { |
| 141 try { |
| 142 num parsedValue = double.parse(value); |
| 143 _max = parsedValue.isNaN ? _max : parsedValue; |
| 144 } catch(e) { |
| 145 _max = null; |
| 146 } finally { |
| 147 _ngModel.validateLater(); |
| 148 } |
| 149 } |
| 150 |
| 151 bool isValid(modelValue) { |
| 152 if (modelValue == null || max == null) return true; |
| 153 |
| 154 try { |
| 155 num parsedValue = double.parse(modelValue.toString()); |
| 156 if (!parsedValue.isNaN) { |
| 157 return parsedValue <= max; |
| 158 } |
| 159 } catch(exception, stackTrace) {} |
| 160 |
| 161 //this validator doesn't care if the type conversation fails or the value |
| 162 //is not a number (NaN) because NgModelNumberValidator will handle the |
| 163 //number-based validation either way. |
| 164 return true; |
| 165 } |
| 166 } |
| 167 |
| 168 /** |
| 169 * Validates the model to see if the numeric value is greater than or equal to t
he min value. |
| 170 */ |
| 171 @Decorator(selector: 'input[type=number][ng-model][min]') |
| 172 @Decorator(selector: 'input[type=range][ng-model][min]') |
| 173 @Decorator( |
| 174 selector: 'input[type=number][ng-model][ng-min]', |
| 175 map: const {'ng-min': '=>min'}) |
| 176 @Decorator( |
| 177 selector: 'input[type=range][ng-model][ng-min]', |
| 178 map: const {'ng-min': '=>min'}) |
| 179 class NgModelMinNumberValidator implements NgValidator { |
| 180 |
| 181 final String name = 'ng-min'; |
| 182 double _min; |
| 183 final NgModel _ngModel; |
| 184 |
| 185 NgModelMinNumberValidator(NgModel this._ngModel) { |
| 186 _ngModel.addValidator(this); |
| 187 } |
| 188 |
| 189 @NgAttr('min') |
| 190 get min => _min; |
| 191 set min(value) { |
| 192 try { |
| 193 num parsedValue = double.parse(value); |
| 194 _min = parsedValue.isNaN ? _min : parsedValue; |
| 195 } catch(e) { |
| 196 _min = null; |
| 197 } finally { |
| 198 _ngModel.validateLater(); |
| 199 } |
| 200 } |
| 201 |
| 202 bool isValid(modelValue) { |
| 203 if (modelValue == null || min == null) return true; |
| 204 |
| 205 try { |
| 206 num parsedValue = double.parse(modelValue.toString()); |
| 207 if (!parsedValue.isNaN) { |
| 208 return parsedValue >= min; |
| 209 } |
| 210 } catch(exception, stackTrace) {} |
| 211 |
| 212 //this validator doesn't care if the type conversation fails or the value |
| 213 //is not a number (NaN) because NgModelNumberValidator will handle the |
| 214 //number-based validation either way. |
| 215 return true; |
| 216 } |
| 217 } |
| 218 |
| 219 /** |
102 * Validates the model to see if its contents match the given pattern present on
either the | 220 * Validates the model to see if its contents match the given pattern present on
either the |
103 * HTML pattern or ng-pattern attributes present on the input element. | 221 * HTML pattern or ng-pattern attributes present on the input element. |
104 */ | 222 */ |
105 @NgDirective(selector: '[ng-model][pattern]') | 223 @Decorator(selector: '[ng-model][pattern]') |
106 @NgDirective( | 224 @Decorator( |
107 selector: '[ng-model][ng-pattern]', | 225 selector: '[ng-model][ng-pattern]', |
108 map: const {'ng-pattern': '=>pattern'}) | 226 map: const {'ng-pattern': '=>pattern'}) |
109 class NgModelPatternValidator implements NgValidatable { | 227 class NgModelPatternValidator implements NgValidator { |
| 228 |
| 229 final String name = 'ng-pattern'; |
110 RegExp _pattern; | 230 RegExp _pattern; |
| 231 final NgModel _ngModel; |
111 | 232 |
112 String get name => 'pattern'; | 233 NgModelPatternValidator(NgModel this._ngModel) { |
113 | 234 _ngModel.addValidator(this); |
114 NgModelPatternValidator(NgModel ngModel) { | |
115 ngModel.addValidator(this); | |
116 } | 235 } |
117 | 236 |
118 bool isValid(value) { | 237 bool isValid(modelValue) { |
119 //remember, only required validates for the input being empty | 238 //remember, only required validates for the input being empty |
120 return _pattern == null || value == null || value.length == 0 || | 239 return _pattern == null || modelValue == null || modelValue.length == 0 || |
121 _pattern.hasMatch(value); | 240 _pattern.hasMatch(modelValue); |
122 } | 241 } |
123 | 242 |
124 @NgAttr('pattern') | 243 @NgAttr('pattern') |
125 set pattern(val) => | 244 void set pattern(val) { |
126 _pattern = val != null && val.length > 0 ? new RegExp(val) : null; | 245 _pattern = val != null && val.length > 0 ? new RegExp(val) : null; |
| 246 _ngModel.validateLater(); |
| 247 } |
127 } | 248 } |
128 | 249 |
129 /** | 250 /** |
130 * Validates the model to see if the length of its contents are greater than or | 251 * Validates the model to see if the length of its contents are greater than or |
131 * equal to the minimum length set in place by the HTML minlength or | 252 * equal to the minimum length set in place by the HTML minlength or |
132 * ng-minlength attributes present on the input element. | 253 * ng-minlength attributes present on the input element. |
133 */ | 254 */ |
134 @NgDirective(selector: '[ng-model][minlength]') | 255 @Decorator(selector: '[ng-model][minlength]') |
135 @NgDirective( | 256 @Decorator( |
136 selector: '[ng-model][ng-minlength]', | 257 selector: '[ng-model][ng-minlength]', |
137 map: const {'ng-minlength': '=>minlength'}) | 258 map: const {'ng-minlength': '=>minlength'}) |
138 class NgModelMinLengthValidator implements NgValidatable { | 259 class NgModelMinLengthValidator implements NgValidator { |
| 260 |
| 261 final String name = 'ng-minlength'; |
139 int _minlength; | 262 int _minlength; |
| 263 final NgModel _ngModel; |
140 | 264 |
141 String get name => 'minlength'; | 265 NgModelMinLengthValidator(NgModel this._ngModel) { |
142 | 266 _ngModel.addValidator(this); |
143 NgModelMinLengthValidator(NgModel ngModel) { | |
144 ngModel.addValidator(this); | |
145 } | 267 } |
146 | 268 |
147 bool isValid(value) { | 269 bool isValid(modelValue) { |
148 //remember, only required validates for the input being empty | 270 //remember, only required validates for the input being empty |
149 return _minlength == 0 || value == null || value.length == 0 || | 271 return _minlength == 0 || modelValue == null || modelValue.length == 0 || |
150 value.length >= _minlength; | 272 modelValue.length >= _minlength; |
151 } | 273 } |
152 | 274 |
153 @NgAttr('minlength') | 275 @NgAttr('minlength') |
154 set minlength(value) => | 276 void set minlength(value) { |
155 _minlength = value == null ? 0 : int.parse(value.toString()); | 277 _minlength = value == null ? 0 : int.parse(value.toString()); |
| 278 _ngModel.validateLater(); |
| 279 } |
156 } | 280 } |
157 | 281 |
158 /** | 282 /** |
159 * Validates the model to see if the length of its contents are less than or | 283 * Validates the model to see if the length of its contents are less than or |
160 * equal to the maximum length set in place by the HTML maxlength or | 284 * equal to the maximum length set in place by the HTML maxlength or |
161 * ng-maxlength attributes present on the input element. | 285 * ng-maxlength attributes present on the input element. |
162 */ | 286 */ |
163 @NgDirective(selector: '[ng-model][maxlength]') | 287 @Decorator(selector: '[ng-model][maxlength]') |
164 @NgDirective( | 288 @Decorator( |
165 selector: '[ng-model][ng-maxlength]', | 289 selector: '[ng-model][ng-maxlength]', |
166 map: const {'ng-maxlength': '=>maxlength'}) | 290 map: const {'ng-maxlength': '=>maxlength'}) |
167 class NgModelMaxLengthValidator implements NgValidatable { | 291 class NgModelMaxLengthValidator implements NgValidator { |
| 292 |
| 293 final String name = 'ng-maxlength'; |
168 int _maxlength = 0; | 294 int _maxlength = 0; |
| 295 final NgModel _ngModel; |
169 | 296 |
170 String get name => 'maxlength'; | 297 NgModelMaxLengthValidator(NgModel this._ngModel) { |
171 | 298 _ngModel.addValidator(this); |
172 NgModelMaxLengthValidator(NgModel ngModel) { | |
173 ngModel.addValidator(this); | |
174 } | 299 } |
175 | 300 |
176 bool isValid(value) => | 301 bool isValid(modelValue) => |
177 _maxlength == 0 || (value == null ? 0 : value.length) <= _maxlength; | 302 _maxlength == 0 || (modelValue == null ? 0 : modelValue.length) <= _maxlen
gth; |
178 | 303 |
179 @NgAttr('maxlength') | 304 @NgAttr('maxlength') |
180 set maxlength(value) => | 305 void set maxlength(value) { |
181 _maxlength = value == null ? 0 : int.parse(value.toString()); | 306 _maxlength = value == null ? 0 : int.parse(value.toString()); |
| 307 _ngModel.validateLater(); |
| 308 } |
182 } | 309 } |
OLD | NEW |