| 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 |