| OLD | NEW |
| 1 library ng_model_spec; | 1 library ng_model_spec; |
| 2 | 2 |
| 3 import '../_specs.dart'; | 3 import '../_specs.dart'; |
| 4 import 'dart:html' as dom; | 4 import 'dart:html' as dom; |
| 5 | 5 |
| 6 void main() { | 6 main() => |
| 7 describe('ng-model', () { | 7 describe('ng-model', () { |
| 8 TestBed _; | 8 TestBed _; |
| 9 | 9 |
| 10 beforeEach(module((Module module) { | 10 beforeEach(inject((TestBed tb) => _ = tb)); |
| 11 module..type(ControllerWithNoLove); | 11 |
| 12 })); | 12 describe('type="text"', () { |
| 13 | 13 it('should update input value from model', inject(() { |
| 14 beforeEach(inject((TestBed tb) => _ = tb)); | 14 _.compile('<input type="text" ng-model="model">'); |
| 15 | 15 _.rootScope.$digest(); |
| 16 describe('type="text" like', () { | 16 |
| 17 it('should update input value from model', inject(() { | 17 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 18 _.compile('<input type="text" ng-model="model">'); | 18 |
| 19 _.rootScope.apply(); | 19 _.rootScope.$apply('model = "misko"'); |
| 20 | 20 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
| 21 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 21 })); |
| 22 | 22 |
| 23 _.rootScope.apply('model = "misko"'); | 23 it('should render null as the empty string', inject(() { |
| 24 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | 24 _.compile('<input type="text" ng-model="model">'); |
| 25 })); | 25 _.rootScope.$digest(); |
| 26 | 26 |
| 27 it('should render null as the empty string', inject(() { | 27 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 28 _.compile('<input type="text" ng-model="model">'); | 28 |
| 29 _.rootScope.apply(); | 29 _.rootScope.$apply('model = null'); |
| 30 | 30 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 31 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 31 })); |
| 32 | 32 |
| 33 _.rootScope.apply('model = null'); | 33 it('should update model from the input value', inject(() { |
| 34 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 34 _.compile('<input type="text" ng-model="model" probe="p">'); |
| 35 })); | 35 Probe probe = _.rootScope.p; |
| 36 | 36 var ngModel = probe.directive(NgModel); |
| 37 it('should update model from the input value', inject(() { | 37 InputElement inputElement = probe.element; |
| 38 _.compile('<input type="text" ng-model="model" probe="p">'); | 38 |
| 39 Probe probe = _.rootScope.context['p']; | 39 inputElement.value = 'abc'; |
| 40 var ngModel = probe.directive(NgModel); | 40 _.triggerEvent(inputElement, 'change'); |
| 41 InputElement inputElement = probe.element; | 41 expect(_.rootScope.model).toEqual('abc'); |
| 42 | 42 |
| 43 inputElement.value = 'abc'; | 43 inputElement.value = 'def'; |
| 44 _.triggerEvent(inputElement, 'change'); | 44 var input = probe.directive(InputTextLikeDirective); |
| 45 expect(_.rootScope.context['model']).toEqual('abc'); | 45 input.processValue(); |
| 46 | 46 expect(_.rootScope.model).toEqual('def'); |
| 47 inputElement.value = 'def'; | 47 })); |
| 48 var input = probe.directive(InputTextLikeDirective); | 48 |
| 49 input.processValue(); | 49 it('should write to input only if value is different', inject(() { |
| 50 expect(_.rootScope.context['model']).toEqual('def'); | 50 var scope = _.rootScope; |
| 51 })); | 51 var element = new dom.InputElement(); |
| 52 | 52 var model = new NgModel(scope, new NodeAttrs(new DivElement()), element, n
ew NgNullForm()); |
| 53 it('should update model from the input value for type=number', inject(() { | 53 dom.querySelector('body').append(element); |
| 54 _.compile('<input type="number" ng-model="model" probe="p">'); | 54 var input = new InputTextLikeDirective(element, model, scope); |
| 55 Probe probe = _.rootScope.context['p']; | 55 |
| 56 var ngModel = probe.directive(NgModel); | 56 element.value = 'abc'; |
| 57 InputElement inputElement = probe.element; | 57 element.selectionStart = 1; |
| 58 | 58 element.selectionEnd = 2; |
| 59 inputElement.value = '12'; | 59 |
| 60 _.triggerEvent(inputElement, 'change'); | 60 model.render('abc'); |
| 61 expect(_.rootScope.context['model']).toEqual(12); | 61 |
| 62 | 62 expect(element.value).toEqual('abc'); |
| 63 inputElement.value = '14'; | 63 // No update. selectionStart/End is unchanged. |
| 64 var input = probe.directive(InputNumberLikeDirective); | 64 expect(element.selectionStart).toEqual(1); |
| 65 input.processValue(); | 65 expect(element.selectionEnd).toEqual(2); |
| 66 expect(_.rootScope.context['model']).toEqual(14); | 66 |
| 67 })); | 67 model.render('xyz'); |
| 68 | 68 |
| 69 it('should update input type=number to blank when model is null', inject((
) { | 69 // Value updated. selectionStart/End changed. |
| 70 _.compile('<input type="number" ng-model="model" probe="p">'); | 70 expect(element.value).toEqual('xyz'); |
| 71 Probe probe = _.rootScope.context['p']; | 71 expect(element.selectionStart).toEqual(3); |
| 72 var ngModel = probe.directive(NgModel); | 72 expect(element.selectionEnd).toEqual(3); |
| 73 InputElement inputElement = probe.element; | 73 })); |
| 74 | 74 }); |
| 75 inputElement.value = '12'; | 75 |
| 76 _.triggerEvent(inputElement, 'change'); | 76 describe('type="password"', () { |
| 77 expect(_.rootScope.context['model']).toEqual(12); | 77 it('should update input value from model', inject(() { |
| 78 | 78 _.compile('<input type="password" ng-model="model">'); |
| 79 _.rootScope.context['model'] = null; | 79 _.rootScope.$digest(); |
| 80 _.rootScope.apply(); | 80 |
| 81 expect(inputElement.value).toEqual(''); | 81 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 82 })); | 82 |
| 83 | 83 _.rootScope.$apply('model = "misko"'); |
| 84 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { | 84 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
| 85 var scope = _.rootScope; | 85 })); |
| 86 var element = new dom.InputElement(); | 86 |
| 87 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | 87 it('should render null as the empty string', inject(() { |
| 88 nodeAttrs['ng-model'] = 'model'; | 88 _.compile('<input type="password" ng-model="model">'); |
| 89 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); | 89 _.rootScope.$digest(); |
| 90 dom.querySelector('body').append(element); | 90 |
| 91 var input = new InputTextLikeDirective(element, model, scope); | 91 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 92 | 92 |
| 93 element | 93 _.rootScope.$apply('model = null'); |
| 94 ..value = 'abc' | 94 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 95 ..selectionStart = 1 | 95 })); |
| 96 ..selectionEnd = 2; | 96 |
| 97 | 97 it('should update model from the input value', inject(() { |
| 98 model.render('abc'); | 98 _.compile('<input type="password" ng-model="model" probe="p">'); |
| 99 | 99 Probe probe = _.rootScope.p; |
| 100 expect(element.value).toEqual('abc'); | 100 var ngModel = probe.directive(NgModel); |
| 101 // No update. selectionStart/End is unchanged. | 101 InputElement inputElement = probe.element; |
| 102 expect(element.selectionStart).toEqual(1); | 102 |
| 103 expect(element.selectionEnd).toEqual(2); | 103 inputElement.value = 'abc'; |
| 104 | 104 _.triggerEvent(inputElement, 'change'); |
| 105 model.render('xyz'); | 105 expect(_.rootScope.model).toEqual('abc'); |
| 106 | 106 |
| 107 // Value updated. selectionStart/End changed. | 107 inputElement.value = 'def'; |
| 108 expect(element.value).toEqual('xyz'); | 108 var input = probe.directive(InputTextLikeDirective); |
| 109 expect(element.selectionStart).toEqual(3); | 109 input.processValue(); |
| 110 expect(element.selectionEnd).toEqual(3); | 110 expect(_.rootScope.model).toEqual('def'); |
| 111 })); | 111 |
| 112 }); | 112 })); |
| 113 | 113 |
| 114 /* This function simulates typing the given text into the input | 114 it('should write to input only if value is different', inject(() { |
| 115 * field. The text will be added wherever the insertion point | 115 var scope = _.rootScope; |
| 116 * happens to be. This method has as side-effect to set the | 116 var element = new dom.InputElement(); |
| 117 * focus on the input (without setting the focus the text | 117 var model = new NgModel(scope, new NodeAttrs(new DivElement()), element, n
ew NgNullForm()); |
| 118 * dispatch may not work). | 118 dom.querySelector('body').append(element); |
| 119 */ | 119 var input = new InputTextLikeDirective(element, model, scope); |
| 120 void simulateTypingText(InputElement input, String text) { | 120 |
| 121 input..focus()..dispatchEvent(new TextEvent('textInput', data: text)); | 121 element.value = 'abc'; |
| 122 } | 122 element.selectionStart = 1; |
| 123 | 123 element.selectionEnd = 2; |
| 124 describe('type="number" like', () { | 124 |
| 125 | 125 model.render('abc'); |
| 126 it('should leave input unchanged when text does not represent a valid numb
er', inject((Injector i) { | 126 |
| 127 var modelFieldName = 'modelForNumFromInvalid1'; | 127 expect(element.value).toEqual('abc'); |
| 128 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); | 128 expect(element.selectionStart).toEqual(1); |
| 129 dom.querySelector('body').append(element); | 129 expect(element.selectionEnd).toEqual(2); |
| 130 | 130 |
| 131 // This test will progressively enter the text '1e1' | 131 model.render('xyz'); |
| 132 // '1' is a valid number. | 132 |
| 133 // '1e' is not a valid number. | 133 expect(element.value).toEqual('xyz'); |
| 134 // '1e1' is again a valid number (with an exponent) | 134 expect(element.selectionStart).toEqual(3); |
| 135 | 135 expect(element.selectionEnd).toEqual(3); |
| 136 simulateTypingText(element, '1'); | 136 })); |
| 137 _.triggerEvent(element, 'change'); | 137 }); |
| 138 expect(element.value).toEqual('1'); | 138 |
| 139 expect(_.rootScope.context[modelFieldName]).toEqual(1); | 139 describe('type="checkbox"', () { |
| 140 | 140 it('should update input value from model', inject((Scope scope) { |
| 141 simulateTypingText(element, 'e'); | 141 var element = _.compile('<input type="checkbox" ng-model="model">'); |
| 142 // Because the text is not a valid number, the element value is empty. | 142 |
| 143 expect(element.value).toEqual(''); | 143 scope.$apply(() { |
| 144 // When the input is invalid, the model is [double.NAN]: | 144 scope['model'] = true; |
| 145 _.triggerEvent(element, 'change'); | |
| 146 expect(_.rootScope.context[modelFieldName].isNaN).toBeTruthy(); | |
| 147 | |
| 148 simulateTypingText(element, '1'); | |
| 149 _.triggerEvent(element, 'change'); | |
| 150 expect(element.value).toEqual('1e1'); | |
| 151 expect(_.rootScope.context[modelFieldName]).toEqual(10); | |
| 152 })); | |
| 153 | |
| 154 it('should not reformat user input to equivalent numeric representation',
inject((Injector i) { | |
| 155 var modelFieldName = 'modelForNumFromInvalid2'; | |
| 156 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); | |
| 157 dom.querySelector('body').append(element); | |
| 158 | |
| 159 simulateTypingText(element, '1e-1'); | |
| 160 expect(element.value).toEqual('1e-1'); | |
| 161 expect(_.rootScope.context[modelFieldName]).toEqual(0.1); | |
| 162 })); | |
| 163 | |
| 164 it('should update input value from model', inject(() { | |
| 165 _.compile('<input type="number" ng-model="model">'); | |
| 166 _.rootScope.apply(); | |
| 167 | |
| 168 _.rootScope.apply('model = 42'); | |
| 169 expect((_.rootElement as dom.InputElement).value).toEqual('42'); | |
| 170 })); | |
| 171 | |
| 172 it('should update input value from model for range inputs', inject(() { | |
| 173 _.compile('<input type="range" ng-model="model">'); | |
| 174 _.rootScope.apply(); | |
| 175 | |
| 176 _.rootScope.apply('model = 42'); | |
| 177 expect((_.rootElement as dom.InputElement).value).toEqual('42'); | |
| 178 })); | |
| 179 | |
| 180 it('should update model from the input value', inject(() { | |
| 181 _.compile('<input type="number" ng-model="model" probe="p">'); | |
| 182 Probe probe = _.rootScope.context['p']; | |
| 183 var ngModel = probe.directive(NgModel); | |
| 184 InputElement inputElement = probe.element; | |
| 185 | |
| 186 inputElement.value = '42'; | |
| 187 _.triggerEvent(inputElement, 'change'); | |
| 188 expect(_.rootScope.context['model']).toEqual(42); | |
| 189 | |
| 190 inputElement.value = '43'; | |
| 191 var input = probe.directive(InputNumberLikeDirective); | |
| 192 input.processValue(); | |
| 193 expect(_.rootScope.context['model']).toEqual(43); | |
| 194 })); | |
| 195 | |
| 196 it('should update model to NaN from a blank input value', inject(() { | |
| 197 _.compile('<input type="number" ng-model="model" probe="p">'); | |
| 198 Probe probe = _.rootScope.context['p']; | |
| 199 var ngModel = probe.directive(NgModel); | |
| 200 InputElement inputElement = probe.element; | |
| 201 | |
| 202 inputElement.value = ''; | |
| 203 _.triggerEvent(inputElement, 'change'); | |
| 204 expect(_.rootScope.context['model'].isNaN).toBeTruthy(); | |
| 205 })); | |
| 206 | |
| 207 it('should update model from the input value for range inputs', inject(()
{ | |
| 208 _.compile('<input type="range" ng-model="model" probe="p">'); | |
| 209 Probe probe = _.rootScope.context['p']; | |
| 210 var ngModel = probe.directive(NgModel); | |
| 211 InputElement inputElement = probe.element; | |
| 212 | |
| 213 inputElement.value = '42'; | |
| 214 _.triggerEvent(inputElement, 'change'); | |
| 215 expect(_.rootScope.context['model']).toEqual(42); | |
| 216 | |
| 217 inputElement.value = '43'; | |
| 218 var input = probe.directive(InputNumberLikeDirective); | |
| 219 input.processValue(); | |
| 220 expect(_.rootScope.context['model']).toEqual(43); | |
| 221 })); | |
| 222 | |
| 223 it('should update model to a native default value from a blank range input
value', inject(() { | |
| 224 _.compile('<input type="range" ng-model="model" probe="p">'); | |
| 225 Probe probe = _.rootScope.context['p']; | |
| 226 var ngModel = probe.directive(NgModel); | |
| 227 InputElement inputElement = probe.element; | |
| 228 | |
| 229 inputElement.value = ''; | |
| 230 _.triggerEvent(inputElement, 'change'); | |
| 231 expect(_.rootScope.context['model']).toBeDefined(); | |
| 232 })); | |
| 233 | |
| 234 it('should render null as blank', inject(() { | |
| 235 _.compile('<input type="number" ng-model="model">'); | |
| 236 _.rootScope.apply(); | |
| 237 | |
| 238 _.rootScope.apply('model = null'); | |
| 239 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 240 })); | |
| 241 | |
| 242 }); | |
| 243 | |
| 244 describe('type="password"', () { | |
| 245 it('should update input value from model', inject(() { | |
| 246 _.compile('<input type="password" ng-model="model">'); | |
| 247 _.rootScope.apply(); | |
| 248 | |
| 249 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 250 | |
| 251 _.rootScope.apply('model = "misko"'); | |
| 252 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | |
| 253 })); | |
| 254 | |
| 255 it('should render null as the empty string', inject(() { | |
| 256 _.compile('<input type="password" ng-model="model">'); | |
| 257 _.rootScope.apply(); | |
| 258 | |
| 259 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 260 | |
| 261 _.rootScope.apply('model = null'); | |
| 262 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 263 })); | |
| 264 | |
| 265 it('should update model from the input value', inject(() { | |
| 266 _.compile('<input type="password" ng-model="model" probe="p">'); | |
| 267 Probe probe = _.rootScope.context['p']; | |
| 268 var ngModel = probe.directive(NgModel); | |
| 269 InputElement inputElement = probe.element; | |
| 270 | |
| 271 inputElement.value = 'abc'; | |
| 272 _.triggerEvent(inputElement, 'change'); | |
| 273 expect(_.rootScope.context['model']).toEqual('abc'); | |
| 274 | |
| 275 inputElement.value = 'def'; | |
| 276 var input = probe.directive(InputTextLikeDirective); | |
| 277 input.processValue(); | |
| 278 expect(_.rootScope.context['model']).toEqual('def'); | |
| 279 | |
| 280 })); | |
| 281 | |
| 282 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { | |
| 283 var scope = _.rootScope; | |
| 284 var element = new dom.InputElement(); | |
| 285 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | |
| 286 nodeAttrs['ng-model'] = 'model'; | |
| 287 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); | |
| 288 dom.querySelector('body').append(element); | |
| 289 var input = new InputTextLikeDirective(element, model, scope); | |
| 290 | |
| 291 element | |
| 292 ..value = 'abc' | |
| 293 ..selectionStart = 1 | |
| 294 ..selectionEnd = 2; | |
| 295 | |
| 296 model.render('abc'); | |
| 297 | |
| 298 expect(element.value).toEqual('abc'); | |
| 299 expect(element.selectionStart).toEqual(1); | |
| 300 expect(element.selectionEnd).toEqual(2); | |
| 301 | |
| 302 model.render('xyz'); | |
| 303 | |
| 304 expect(element.value).toEqual('xyz'); | |
| 305 expect(element.selectionStart).toEqual(3); | |
| 306 expect(element.selectionEnd).toEqual(3); | |
| 307 })); | |
| 308 }); | |
| 309 | |
| 310 describe('type="search"', () { | |
| 311 it('should update input value from model', inject(() { | |
| 312 _.compile('<input type="search" ng-model="model">'); | |
| 313 _.rootScope.apply(); | |
| 314 | |
| 315 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 316 | |
| 317 _.rootScope.apply('model = "misko"'); | |
| 318 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | |
| 319 })); | |
| 320 | |
| 321 it('should render null as the empty string', inject(() { | |
| 322 _.compile('<input type="search" ng-model="model">'); | |
| 323 _.rootScope.apply(); | |
| 324 | |
| 325 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 326 | |
| 327 _.rootScope.apply('model = null'); | |
| 328 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 329 })); | |
| 330 | |
| 331 it('should update model from the input value', inject(() { | |
| 332 _.compile('<input type="search" ng-model="model" probe="p">'); | |
| 333 Probe probe = _.rootScope.context['p']; | |
| 334 var ngModel = probe.directive(NgModel); | |
| 335 InputElement inputElement = probe.element; | |
| 336 | |
| 337 inputElement.value = 'abc'; | |
| 338 _.triggerEvent(inputElement, 'change'); | |
| 339 expect(_.rootScope.context['model']).toEqual('abc'); | |
| 340 | |
| 341 inputElement.value = 'def'; | |
| 342 var input = probe.directive(InputTextLikeDirective); | |
| 343 input.processValue(); | |
| 344 expect(_.rootScope.context['model']).toEqual('def'); | |
| 345 })); | |
| 346 | |
| 347 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { | |
| 348 var scope = _.rootScope; | |
| 349 var element = new dom.InputElement(); | |
| 350 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | |
| 351 nodeAttrs['ng-model'] = 'model'; | |
| 352 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); | |
| 353 dom.querySelector('body').append(element); | |
| 354 var input = new InputTextLikeDirective(element, model, scope); | |
| 355 | |
| 356 element | |
| 357 ..value = 'abc' | |
| 358 ..selectionStart = 1 | |
| 359 ..selectionEnd = 2; | |
| 360 | |
| 361 model.render('abc'); | |
| 362 | |
| 363 expect(element.value).toEqual('abc'); | |
| 364 // No update. selectionStart/End is unchanged. | |
| 365 expect(element.selectionStart).toEqual(1); | |
| 366 expect(element.selectionEnd).toEqual(2); | |
| 367 | |
| 368 model.render('xyz'); | |
| 369 | |
| 370 // Value updated. selectionStart/End changed. | |
| 371 expect(element.value).toEqual('xyz'); | |
| 372 expect(element.selectionStart).toEqual(3); | |
| 373 expect(element.selectionEnd).toEqual(3); | |
| 374 })); | |
| 375 }); | |
| 376 | |
| 377 describe('no type attribute', () { | |
| 378 it('should be set "text" as default value for "type" attribute', inject(()
{ | |
| 379 _.compile('<input ng-model="model">'); | |
| 380 _.rootScope.apply(); | |
| 381 expect((_.rootElement as dom.InputElement).attributes['type']).toEqual('
text'); | |
| 382 })); | |
| 383 | |
| 384 it('should update input value from model', inject(() { | |
| 385 _.compile('<input ng-model="model">'); | |
| 386 _.rootScope.apply(); | |
| 387 | |
| 388 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 389 | |
| 390 _.rootScope.apply('model = "misko"'); | |
| 391 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | |
| 392 })); | |
| 393 | |
| 394 it('should render null as the empty string', inject(() { | |
| 395 _.compile('<input ng-model="model">'); | |
| 396 _.rootScope.apply(); | |
| 397 | |
| 398 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 399 | |
| 400 _.rootScope.apply('model = null'); | |
| 401 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 402 })); | |
| 403 | |
| 404 it('should update model from the input value', inject(() { | |
| 405 _.compile('<input ng-model="model" probe="p">'); | |
| 406 Probe probe = _.rootScope.context['p']; | |
| 407 var ngModel = probe.directive(NgModel); | |
| 408 InputElement inputElement = probe.element; | |
| 409 | |
| 410 inputElement.value = 'abc'; | |
| 411 _.triggerEvent(inputElement, 'change'); | |
| 412 expect(_.rootScope.context['model']).toEqual('abc'); | |
| 413 | |
| 414 inputElement.value = 'def'; | |
| 415 var input = probe.directive(InputTextLikeDirective); | |
| 416 input.processValue(); | |
| 417 expect(_.rootScope.context['model']).toEqual('def'); | |
| 418 })); | |
| 419 | |
| 420 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { | |
| 421 var scope = _.rootScope; | |
| 422 var element = new dom.InputElement(); | |
| 423 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | |
| 424 nodeAttrs['ng-model'] = 'model'; | |
| 425 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); | |
| 426 dom.querySelector('body').append(element); | |
| 427 var input = new InputTextLikeDirective(element, model, scope); | |
| 428 | |
| 429 element | |
| 430 ..value = 'abc' | |
| 431 ..selectionStart = 1 | |
| 432 ..selectionEnd = 2; | |
| 433 | |
| 434 model.render('abc'); | |
| 435 | |
| 436 expect(element.value).toEqual('abc'); | |
| 437 expect(element.selectionStart).toEqual(1); | |
| 438 expect(element.selectionEnd).toEqual(2); | |
| 439 | |
| 440 model.render('xyz'); | |
| 441 | |
| 442 expect(element.value).toEqual('xyz'); | |
| 443 expect(element.selectionStart).toEqual(3); | |
| 444 expect(element.selectionEnd).toEqual(3); | |
| 445 })); | |
| 446 }); | |
| 447 | |
| 448 describe('type="checkbox"', () { | |
| 449 it('should update input value from model', inject((Scope scope) { | |
| 450 var element = _.compile('<input type="checkbox" ng-model="model">'); | |
| 451 | |
| 452 scope.apply(() { | |
| 453 scope.context['model'] = true; | |
| 454 }); | |
| 455 expect(element.checked).toBe(true); | |
| 456 | |
| 457 scope.apply(() { | |
| 458 scope.context['model'] = false; | |
| 459 }); | |
| 460 expect(element.checked).toBe(false); | |
| 461 })); | |
| 462 | |
| 463 it('should render as dirty when checked', inject((Scope scope) { | |
| 464 var element = _.compile('<input type="text" ng-model="my_model" probe="i
" />'); | |
| 465 Probe probe = _.rootScope.context['i']; | |
| 466 var model = probe.directive(NgModel); | |
| 467 | |
| 468 expect(model.pristine).toEqual(true); | |
| 469 expect(model.dirty).toEqual(false); | |
| 470 | |
| 471 _.triggerEvent(element, 'change'); | |
| 472 | |
| 473 expect(model.pristine).toEqual(false); | |
| 474 expect(model.dirty).toEqual(true); | |
| 475 })); | |
| 476 | |
| 477 | |
| 478 it('should update input value from model using ng-true-value/false', injec
t((Scope scope) { | |
| 479 var element = _.compile('<input type="checkbox" ng-model="model" ng-true
-value="1" ng-false-value="0">'); | |
| 480 | |
| 481 scope.apply(() { | |
| 482 scope.context['model'] = 1; | |
| 483 }); | |
| 484 expect(element.checked).toBe(true); | |
| 485 | |
| 486 scope.apply(() { | |
| 487 scope.context['model'] = 0; | |
| 488 }); | |
| 489 expect(element.checked).toBe(false); | |
| 490 | |
| 491 element.checked = true; | |
| 492 _.triggerEvent(element, 'change'); | |
| 493 expect(scope.context['model']).toBe(1); | |
| 494 | |
| 495 element.checked = false; | |
| 496 _.triggerEvent(element, 'change'); | |
| 497 expect(scope.context['model']).toBe(0); | |
| 498 })); | |
| 499 | |
| 500 | |
| 501 it('should allow non boolean values like null, 0, 1', inject((Scope scope)
{ | |
| 502 var element = _.compile('<input type="checkbox" ng-model="model">'); | |
| 503 | |
| 504 scope.apply(() { | |
| 505 scope.context['model'] = 0; | |
| 506 }); | |
| 507 expect(element.checked).toBe(false); | |
| 508 | |
| 509 scope.apply(() { | |
| 510 scope.context['model'] = 1; | |
| 511 }); | |
| 512 expect(element.checked).toBe(true); | |
| 513 | |
| 514 scope.apply(() { | |
| 515 scope.context['model'] = null; | |
| 516 }); | |
| 517 expect(element.checked).toBe(false); | |
| 518 })); | |
| 519 | |
| 520 | |
| 521 it('should update model from the input value', inject((Scope scope) { | |
| 522 var element = _.compile('<input type="checkbox" ng-model="model">'); | |
| 523 | |
| 524 element.checked = true; | |
| 525 _.triggerEvent(element, 'change'); | |
| 526 expect(scope.context['model']).toBe(true); | |
| 527 | |
| 528 element.checked = false; | |
| 529 _.triggerEvent(element, 'change'); | |
| 530 expect(scope.context['model']).toBe(false); | |
| 531 })); | |
| 532 }); | |
| 533 | |
| 534 describe('textarea', () { | |
| 535 it('should update textarea value from model', inject(() { | |
| 536 _.compile('<textarea ng-model="model">'); | |
| 537 _.rootScope.apply(); | |
| 538 | |
| 539 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); | |
| 540 | |
| 541 _.rootScope.apply('model = "misko"'); | |
| 542 expect((_.rootElement as dom.TextAreaElement).value).toEqual('misko'); | |
| 543 })); | |
| 544 | |
| 545 it('should render null as the empty string', inject(() { | |
| 546 _.compile('<textarea ng-model="model">'); | |
| 547 _.rootScope.apply(); | |
| 548 | |
| 549 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); | |
| 550 | |
| 551 _.rootScope.apply('model = null'); | |
| 552 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); | |
| 553 })); | |
| 554 | |
| 555 it('should update model from the input value', inject(() { | |
| 556 _.compile('<textarea ng-model="model" probe="p">'); | |
| 557 Probe probe = _.rootScope.context['p']; | |
| 558 var ngModel = probe.directive(NgModel); | |
| 559 TextAreaElement element = probe.element; | |
| 560 | |
| 561 element.value = 'abc'; | |
| 562 _.triggerEvent(element, 'change'); | |
| 563 expect(_.rootScope.context['model']).toEqual('abc'); | |
| 564 | |
| 565 element.value = 'def'; | |
| 566 var textarea = probe.directive(InputTextLikeDirective); | |
| 567 textarea.processValue(); | |
| 568 expect(_.rootScope.context['model']).toEqual('def'); | |
| 569 | |
| 570 })); | |
| 571 | |
| 572 // NOTE(deboer): This test passes on Dartium, but fails in the content_she
ll. | |
| 573 // The Dart team is looking into this bug. | |
| 574 xit('should write to input only if value is different', inject((Injector i
, AstParser parser) { | |
| 575 var scope = _.rootScope; | |
| 576 var element = new dom.TextAreaElement(); | |
| 577 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | |
| 578 nodeAttrs['ng-model'] = 'model'; | |
| 579 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); | |
| 580 dom.querySelector('body').append(element); | |
| 581 var input = new InputTextLikeDirective(element, model, scope); | |
| 582 | |
| 583 element | |
| 584 ..value = 'abc' | |
| 585 ..selectionStart = 1 | |
| 586 ..selectionEnd = 2; | |
| 587 | |
| 588 model.render('abc'); | |
| 589 | |
| 590 expect(element.value).toEqual('abc'); | |
| 591 expect(element.selectionStart).toEqual(1); | |
| 592 expect(element.selectionEnd).toEqual(2); | |
| 593 | |
| 594 model.render('xyz'); | |
| 595 | |
| 596 // Setting the value on a textarea doesn't update the selection the way
it | |
| 597 // does on input elements. This stays unchanged. | |
| 598 expect(element.value).toEqual('xyz'); | |
| 599 expect(element.selectionStart).toEqual(0); | |
| 600 expect(element.selectionEnd).toEqual(0); | |
| 601 })); | |
| 602 }); | |
| 603 | |
| 604 describe('type="radio"', () { | |
| 605 it('should update input value from model', inject(() { | |
| 606 _.compile('<input type="radio" name="color" value="red" ng-model="color"
probe="r">' + | |
| 607 '<input type="radio" name="color" value="green" ng-model="colo
r" probe="g">' + | |
| 608 '<input type="radio" name="color" value="blue" ng-model="color
" probe="b">'); | |
| 609 _.rootScope.apply(); | |
| 610 | |
| 611 RadioButtonInputElement redBtn = _.rootScope.context['r'].element; | |
| 612 RadioButtonInputElement greenBtn = _.rootScope.context['g'].element; | |
| 613 RadioButtonInputElement blueBtn = _.rootScope.context['b'].element; | |
| 614 | |
| 615 expect(redBtn.checked).toBe(false); | |
| 616 expect(greenBtn.checked).toBe(false); | |
| 617 expect(blueBtn.checked).toBe(false); | |
| 618 | |
| 619 // Should change correct element to checked. | |
| 620 _.rootScope.apply('color = "green"'); | |
| 621 | |
| 622 expect(redBtn.checked).toBe(false); | |
| 623 expect(greenBtn.checked).toBe(true); | |
| 624 expect(blueBtn.checked).toBe(false); | |
| 625 | |
| 626 // Non-existing element. | |
| 627 _.rootScope.apply('color = "unknown"'); | |
| 628 | |
| 629 expect(redBtn.checked).toBe(false); | |
| 630 expect(greenBtn.checked).toBe(false); | |
| 631 expect(blueBtn.checked).toBe(false); | |
| 632 | |
| 633 // Should update model with value of checked element. | |
| 634 _.triggerEvent(redBtn, 'click'); | |
| 635 | |
| 636 expect(_.rootScope.context['color']).toEqual('red'); | |
| 637 expect(redBtn.checked).toBe(true); | |
| 638 expect(greenBtn.checked).toBe(false); | |
| 639 expect(blueBtn.checked).toBe(false); | |
| 640 | |
| 641 _.triggerEvent(greenBtn, 'click'); | |
| 642 expect(_.rootScope.context['color']).toEqual('green'); | |
| 643 expect(redBtn.checked).toBe(false); | |
| 644 expect(greenBtn.checked).toBe(true); | |
| 645 expect(blueBtn.checked).toBe(false); | |
| 646 })); | |
| 647 | |
| 648 it('should support ng-value', () { | |
| 649 _.compile('<input type="radio" name="color" ng-value="red" ng-model="col
or" probe="r">' + | |
| 650 '<input type="radio" name="color" ng-value="green" ng-model="c
olor" probe="g">' + | |
| 651 '<input type="radio" name="color" ng-value="blue" ng-model="co
lor" probe="b">'); | |
| 652 | |
| 653 var red = {'name': 'RED'}; | |
| 654 var green = {'name': 'GREEN'}; | |
| 655 var blue = {'name': 'BLUE'}; | |
| 656 _.rootScope.context | |
| 657 ..['red'] = red | |
| 658 ..['green'] = green | |
| 659 ..['blue'] = blue; | |
| 660 | |
| 661 _.rootScope.apply(); | |
| 662 | |
| 663 RadioButtonInputElement redBtn = _.rootScope.context['r'].element; | |
| 664 RadioButtonInputElement greenBtn = _.rootScope.context['g'].element; | |
| 665 RadioButtonInputElement blueBtn = _.rootScope.context['b'].element; | |
| 666 | |
| 667 expect(redBtn.checked).toBe(false); | |
| 668 expect(greenBtn.checked).toBe(false); | |
| 669 expect(blueBtn.checked).toBe(false); | |
| 670 | |
| 671 // Should change correct element to checked. | |
| 672 _.rootScope.context['color'] = green; | |
| 673 _.rootScope.apply(); | |
| 674 | |
| 675 expect(redBtn.checked).toBe(false); | |
| 676 expect(greenBtn.checked).toBe(true); | |
| 677 expect(blueBtn.checked).toBe(false); | |
| 678 | |
| 679 // Non-existing element. | |
| 680 _.rootScope.context['color'] = {}; | |
| 681 _.rootScope.apply(); | |
| 682 | |
| 683 expect(redBtn.checked).toBe(false); | |
| 684 expect(greenBtn.checked).toBe(false); | |
| 685 expect(blueBtn.checked).toBe(false); | |
| 686 | |
| 687 // Should update model with value of checked element. | |
| 688 _.triggerEvent(redBtn, 'click'); | |
| 689 | |
| 690 expect(_.rootScope.context['color']).toEqual(red); | |
| 691 expect(redBtn.checked).toBe(true); | |
| 692 expect(greenBtn.checked).toBe(false); | |
| 693 expect(blueBtn.checked).toBe(false); | |
| 694 | |
| 695 _.triggerEvent(greenBtn, 'click'); | |
| 696 expect(_.rootScope.context['color']).toEqual(green); | |
| 697 expect(redBtn.checked).toBe(false); | |
| 698 expect(greenBtn.checked).toBe(true); | |
| 699 expect(blueBtn.checked).toBe(false); | |
| 700 }); | 145 }); |
| 701 | 146 expect(element.checked).toBe(true); |
| 702 it('should render as dirty when checked', inject((Scope scope) { | 147 |
| 703 var element = _.compile( | 148 scope.$apply(() { |
| 704 '<div>' + | 149 scope['model'] = false; |
| 705 ' <input type="radio" id="on" ng-model="my_model" probe="i" value="on
" />' + | |
| 706 ' <input type="radio" id="off" ng-model="my_model" probe="j" value="o
ff" />' + | |
| 707 '</div>' | |
| 708 ); | |
| 709 Probe probe = _.rootScope.context['i']; | |
| 710 | |
| 711 var model = probe.directive(NgModel); | |
| 712 | |
| 713 var input1 = element.querySelector("#on"); | |
| 714 var input2 = element.querySelector("#off"); | |
| 715 | |
| 716 expect(model.pristine).toEqual(true); | |
| 717 expect(model.dirty).toEqual(false); | |
| 718 | |
| 719 expect(input1.classes.contains("ng-dirty")).toBe(false); | |
| 720 expect(input2.classes.contains("ng-dirty")).toBe(false); | |
| 721 expect(input1.classes.contains("ng-pristine")).toBe(true); | |
| 722 expect(input1.classes.contains("ng-pristine")).toBe(true); | |
| 723 | |
| 724 input1.checked = true; | |
| 725 _.triggerEvent(input1, 'click'); | |
| 726 | |
| 727 expect(model.pristine).toEqual(false); | |
| 728 expect(model.dirty).toEqual(true); | |
| 729 | |
| 730 input1.checked = false; | |
| 731 input2.checked = true; | |
| 732 _.triggerEvent(input2, 'click'); | |
| 733 | |
| 734 expect(input1.classes.contains("ng-dirty")).toBe(true); | |
| 735 expect(input2.classes.contains("ng-dirty")).toBe(true); | |
| 736 expect(input1.classes.contains("ng-pristine")).toBe(false); | |
| 737 expect(input1.classes.contains("ng-pristine")).toBe(false); | |
| 738 })); | |
| 739 }); | |
| 740 | |
| 741 describe('type="search"', () { | |
| 742 it('should update input value from model', inject(() { | |
| 743 _.compile('<input type="search" ng-model="model">'); | |
| 744 _.rootScope.apply(); | |
| 745 | |
| 746 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 747 | |
| 748 _.rootScope.apply('model = "matias"'); | |
| 749 expect((_.rootElement as dom.InputElement).value).toEqual('matias'); | |
| 750 })); | |
| 751 | |
| 752 it('should render null as the empty string', inject(() { | |
| 753 _.compile('<input type="search" ng-model="model">'); | |
| 754 _.rootScope.apply(); | |
| 755 | |
| 756 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 757 | |
| 758 _.rootScope.apply('model = null'); | |
| 759 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 760 })); | |
| 761 | |
| 762 it('should update model from the input value', inject(() { | |
| 763 _.compile('<input type="search" ng-model="model" probe="p">'); | |
| 764 Probe probe = _.rootScope.context['p']; | |
| 765 var ngModel = probe.directive(NgModel); | |
| 766 InputElement inputElement = probe.element; | |
| 767 | |
| 768 inputElement.value = 'xzy'; | |
| 769 _.triggerEvent(inputElement, 'change'); | |
| 770 expect(_.rootScope.context['model']).toEqual('xzy'); | |
| 771 | |
| 772 inputElement.value = '123'; | |
| 773 var input = probe.directive(InputTextLikeDirective); | |
| 774 input.processValue(); | |
| 775 expect(_.rootScope.context['model']).toEqual('123'); | |
| 776 })); | |
| 777 }); | |
| 778 | |
| 779 describe('contenteditable', () { | |
| 780 it('should update content from model', inject(() { | |
| 781 _.compile('<p contenteditable ng-model="model">'); | |
| 782 _.rootScope.apply(); | |
| 783 | |
| 784 expect(_.rootElement.text).toEqual(''); | |
| 785 | |
| 786 _.rootScope.apply('model = "misko"'); | |
| 787 expect(_.rootElement.text).toEqual('misko'); | |
| 788 })); | |
| 789 | |
| 790 it('should update model from the input value', inject(() { | |
| 791 _.compile('<p contenteditable ng-model="model">'); | |
| 792 Element element = _.rootElement; | |
| 793 | |
| 794 element.innerHtml = 'abc'; | |
| 795 _.triggerEvent(element, 'change'); | |
| 796 expect(_.rootScope.context['model']).toEqual('abc'); | |
| 797 | |
| 798 element.innerHtml = 'def'; | |
| 799 var input = ngInjector(element).get(ContentEditableDirective); | |
| 800 input.processValue(); | |
| 801 expect(_.rootScope.context['model']).toEqual('def'); | |
| 802 })); | |
| 803 }); | |
| 804 | |
| 805 describe('pristine / dirty', () { | |
| 806 it('should be set to pristine by default', inject((Scope scope) { | |
| 807 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | |
| 808 Probe probe = _.rootScope.context['i']; | |
| 809 var model = probe.directive(NgModel); | |
| 810 | |
| 811 expect(model.pristine).toEqual(true); | |
| 812 expect(model.dirty).toEqual(false); | |
| 813 })); | |
| 814 | |
| 815 it('should add and remove the correct CSS classes when set to dirty and to
pristine', inject((Scope scope) { | |
| 816 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | |
| 817 Probe probe = _.rootScope.context['i']; | |
| 818 NgModel model = probe.directive(NgModel); | |
| 819 InputElement element = probe.element; | |
| 820 | |
| 821 model.dirty = true; | |
| 822 expect(model.pristine).toEqual(false); | |
| 823 expect(model.dirty).toEqual(true); | |
| 824 expect(element.classes.contains('ng-pristine')).toBe(false); | |
| 825 expect(element.classes.contains('ng-dirty')).toBe(true); | |
| 826 | |
| 827 model.pristine = true; | |
| 828 expect(model.pristine).toEqual(true); | |
| 829 expect(model.dirty).toEqual(false); | |
| 830 expect(element.classes.contains('ng-pristine')).toBe(true); | |
| 831 expect(element.classes.contains('ng-dirty')).toBe(false); | |
| 832 })); | |
| 833 | |
| 834 it('should render the parent form/fieldset as dirty but not the other mode
ls', inject((Scope scope) { | |
| 835 _.compile('<form name="myForm">' + | |
| 836 ' <fieldset name="myFieldset">' + | |
| 837 ' <input type="text" ng-model="my_model1" probe="myModel1"
/>' + | |
| 838 ' <input type="text" ng-model="my_model2" probe="myModel2"
/>' + | |
| 839 ' </fieldset>' + | |
| 840 '</form>'); | |
| 841 | |
| 842 var inputElement1 = _.rootScope.context['myModel1'].element; | |
| 843 var inputElement2 = _.rootScope.context['myModel2'].element; | |
| 844 var formElement = _.rootScope.context['myForm'].element; | |
| 845 var fieldsetElement = _.rootScope.context['myFieldset'].element; | |
| 846 | |
| 847 expect(formElement.classes.contains('ng-pristine')).toBe(true); | |
| 848 expect(formElement.classes.contains('ng-dirty')).toBe(false); | |
| 849 | |
| 850 expect(fieldsetElement.classes.contains('ng-pristine')).toBe(true); | |
| 851 expect(fieldsetElement.classes.contains('ng-dirty')).toBe(false); | |
| 852 | |
| 853 expect(inputElement1.classes.contains('ng-pristine')).toBe(true); | |
| 854 expect(inputElement1.classes.contains('ng-dirty')).toBe(false); | |
| 855 | |
| 856 expect(inputElement2.classes.contains('ng-pristine')).toBe(true); | |
| 857 expect(inputElement2.classes.contains('ng-dirty')).toBe(false); | |
| 858 | |
| 859 inputElement1.value = '...hi...'; | |
| 860 _.triggerEvent(inputElement1, 'change'); | |
| 861 | |
| 862 expect(formElement.classes.contains('ng-pristine')).toBe(false); | |
| 863 expect(formElement.classes.contains('ng-dirty')).toBe(true); | |
| 864 | |
| 865 expect(fieldsetElement.classes.contains('ng-pristine')).toBe(false); | |
| 866 expect(fieldsetElement.classes.contains('ng-dirty')).toBe(true); | |
| 867 | |
| 868 expect(inputElement1.classes.contains('ng-pristine')).toBe(false); | |
| 869 expect(inputElement1.classes.contains('ng-dirty')).toBe(true); | |
| 870 | |
| 871 expect(inputElement2.classes.contains('ng-pristine')).toBe(true); | |
| 872 expect(inputElement2.classes.contains('ng-dirty')).toBe(false); | |
| 873 })); | |
| 874 }); | |
| 875 | |
| 876 describe('validation', () { | |
| 877 it('should happen automatically when the scope changes', inject((Scope sco
pe) { | |
| 878 _.compile('<input type="text" ng-model="model" probe="i" required>'); | |
| 879 _.rootScope.apply(); | |
| 880 | |
| 881 Probe probe = _.rootScope.context['i']; | |
| 882 var model = probe.directive(NgModel); | |
| 883 | |
| 884 expect(model.invalid).toBe(true); | |
| 885 expect(model.valid).toBe(false); | |
| 886 | |
| 887 _.rootScope.apply('model = "viljami"'); | |
| 888 | |
| 889 expect(model.invalid).toBe(false); | |
| 890 expect(model.valid).toBe(true); | |
| 891 })); | |
| 892 | |
| 893 it('should happen automatically upon user input via the onInput event', in
ject(() { | |
| 894 _.compile('<input type="text" ng-model="model" probe="i" required>'); | |
| 895 | |
| 896 Probe probe = _.rootScope.context['i']; | |
| 897 var model = probe.directive(NgModel); | |
| 898 InputElement inputElement = model.element; | |
| 899 | |
| 900 expect(model.invalid).toBe(true); | |
| 901 expect(model.valid).toBe(false); | |
| 902 | |
| 903 inputElement.value = 'some value'; | |
| 904 _.triggerEvent(inputElement, 'input'); | |
| 905 | |
| 906 expect(model.invalid).toBe(false); | |
| 907 expect(model.valid).toBe(true); | |
| 908 })); | |
| 909 }); | |
| 910 | |
| 911 describe('valid / invalid', () { | |
| 912 it('should add and remove the correct flags when set to valid and to inval
id', inject((Scope scope) { | |
| 913 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | |
| 914 Probe probe = _.rootScope.context['i']; | |
| 915 var model = probe.directive(NgModel); | |
| 916 InputElement element = probe.element; | |
| 917 | |
| 918 model.invalid = true; | |
| 919 expect(model.valid).toEqual(false); | |
| 920 expect(model.invalid).toEqual(true); | |
| 921 expect(element.classes.contains('ng-valid')).toBe(false); | |
| 922 expect(element.classes.contains('ng-invalid')).toBe(true); | |
| 923 | |
| 924 model.valid = true; | |
| 925 expect(model.valid).toEqual(true); | |
| 926 expect(model.invalid).toEqual(false); | |
| 927 expect(element.classes.contains('ng-invalid')).toBe(false); | |
| 928 expect(element.classes.contains('ng-valid')).toBe(true); | |
| 929 })); | |
| 930 | |
| 931 it('should set the validity with respect to all existing validations when
setValidity() is used', inject((Scope scope) { | |
| 932 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | |
| 933 Probe probe = _.rootScope.context['i']; | |
| 934 var model = probe.directive(NgModel); | |
| 935 | |
| 936 model.setValidity("required", false); | |
| 937 expect(model.valid).toEqual(false); | |
| 938 expect(model.invalid).toEqual(true); | |
| 939 | |
| 940 model.setValidity("format", false); | |
| 941 expect(model.valid).toEqual(false); | |
| 942 expect(model.invalid).toEqual(true); | |
| 943 | |
| 944 model.setValidity("format", true); | |
| 945 expect(model.valid).toEqual(false); | |
| 946 expect(model.invalid).toEqual(true); | |
| 947 | |
| 948 model.setValidity("required", true); | |
| 949 expect(model.valid).toEqual(true); | |
| 950 expect(model.invalid).toEqual(false); | |
| 951 })); | |
| 952 | |
| 953 it('should register each error only once when invalid', inject((Scope scop
e) { | |
| 954 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | |
| 955 Probe probe = _.rootScope.context['i']; | |
| 956 var model = probe.directive(NgModel); | |
| 957 | |
| 958 model.setValidity("distinct-error", false); | |
| 959 expect(model.valid).toEqual(false); | |
| 960 expect(model.invalid).toEqual(true); | |
| 961 | |
| 962 model.setValidity("distinct-error", false); | |
| 963 expect(model.valid).toEqual(false); | |
| 964 expect(model.invalid).toEqual(true); | |
| 965 | |
| 966 model.setValidity("distinct-error", true); | |
| 967 expect(model.valid).toEqual(true); | |
| 968 expect(model.invalid).toEqual(false); | |
| 969 })); | |
| 970 }); | |
| 971 | |
| 972 describe('text-like events', () { | |
| 973 it('should update the binding on the "input" event', inject(() { | |
| 974 _.compile('<input type="text" ng-model="model" probe="p">'); | |
| 975 Probe probe = _.rootScope.context['p']; | |
| 976 InputElement inputElement = probe.element; | |
| 977 | |
| 978 inputElement.value = 'waaaah'; | |
| 979 | |
| 980 expect(_.rootScope.context['model']).not.toEqual('waaaah'); | |
| 981 | |
| 982 _.triggerEvent(inputElement, 'input'); | |
| 983 | |
| 984 expect(_.rootScope.context['model']).toEqual('waaaah'); | |
| 985 })); | |
| 986 }); | |
| 987 | |
| 988 describe('error messages', () { | |
| 989 it('should produce a useful error for bad ng-model expressions', () { | |
| 990 expect(async(() { | |
| 991 _.compile('<div no-love><textarea ng-model=ctrl.love probe="loveProbe"
></textarea></div'); | |
| 992 Probe probe = _.rootScope.context['loveProbe']; | |
| 993 TextAreaElement inputElement = probe.element; | |
| 994 | |
| 995 inputElement.value = 'xzy'; | |
| 996 _.triggerEvent(inputElement, 'change'); | |
| 997 _.rootScope.apply(); | |
| 998 })).toThrow('love'); | |
| 999 | |
| 1000 }); | 150 }); |
| 1001 }); | 151 expect(element.checked).toBe(false); |
| 1002 | 152 })); |
| 1003 describe('reset()', () { | 153 |
| 1004 it('should reset the model value to its original state', () { | 154 |
| 1005 _.compile('<input type="text" ng-model="myModel" probe="i" />'); | 155 it('should allow non boolean values like null, 0, 1', inject((Scope scope) { |
| 1006 _.rootScope.apply('myModel = "animal"'); | 156 var element = _.compile('<input type="checkbox" ng-model="model">'); |
| 1007 | 157 |
| 1008 Probe probe = _.rootScope.context['i']; | 158 scope.$apply(() { |
| 1009 var model = probe.directive(NgModel); | 159 scope['model'] = 0; |
| 1010 | |
| 1011 expect(_.rootScope.context['myModel']).toEqual('animal'); | |
| 1012 expect(model.modelValue).toEqual('animal'); | |
| 1013 expect(model.viewValue).toEqual('animal'); | |
| 1014 | |
| 1015 _.rootScope.apply('myModel = "man"'); | |
| 1016 | |
| 1017 expect(_.rootScope.context['myModel']).toEqual('man'); | |
| 1018 expect(model.modelValue).toEqual('man'); | |
| 1019 expect(model.viewValue).toEqual('man'); | |
| 1020 | |
| 1021 model.reset(); | |
| 1022 | |
| 1023 expect(_.rootScope.context['myModel']).toEqual('animal'); | |
| 1024 expect(model.modelValue).toEqual('animal'); | |
| 1025 expect(model.viewValue).toEqual('animal'); | |
| 1026 }); | 160 }); |
| 1027 }); | 161 expect(element.checked).toBe(false); |
| 1028 | 162 |
| 1029 it('should set the model to be untouched when the model is reset', () { | 163 scope.$apply(() { |
| 1030 var input = _.compile('<input type="text" ng-model="myModel" probe="i" />'
); | 164 scope['model'] = 1; |
| 1031 var model = _.rootScope.context['i'].directive(NgModel); | 165 }); |
| 1032 | 166 expect(element.checked).toBe(true); |
| 1033 expect(model.touched).toBe(false); | 167 |
| 1034 expect(model.untouched).toBe(true); | 168 scope.$apply(() { |
| 1035 | 169 scope['model'] = null; |
| 1036 _.triggerEvent(input, 'blur'); | 170 }); |
| 1037 | 171 expect(element.checked).toBe(false); |
| 1038 expect(model.touched).toBe(true); | 172 })); |
| 1039 expect(model.untouched).toBe(false); | 173 |
| 1040 | 174 |
| 1041 model.reset(); | 175 it('should update model from the input value', inject((Scope scope) { |
| 1042 | 176 var element = _.compile('<input type="checkbox" ng-model="model">'); |
| 1043 expect(model.touched).toBe(false); | 177 |
| 1044 expect(model.untouched).toBe(true); | 178 element.checked = true; |
| 1045 }); | 179 _.triggerEvent(element, 'change'); |
| 1046 }); | 180 expect(scope['model']).toBe(true); |
| 1047 } | 181 |
| 1048 | 182 element.checked = false; |
| 1049 @NgController( | 183 _.triggerEvent(element, 'change'); |
| 1050 selector: '[no-love]', | 184 expect(scope['model']).toBe(false); |
| 1051 publishAs: 'ctrl') | 185 })); |
| 1052 class ControllerWithNoLove { | 186 }); |
| 1053 var apathy = null; | 187 |
| 1054 } | 188 describe('type="textarea"', () { |
| 189 it('should update textarea value from model', inject(() { |
| 190 _.compile('<textarea ng-model="model">'); |
| 191 _.rootScope.$digest(); |
| 192 |
| 193 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); |
| 194 |
| 195 _.rootScope.$apply('model = "misko"'); |
| 196 expect((_.rootElement as dom.TextAreaElement).value).toEqual('misko'); |
| 197 })); |
| 198 |
| 199 it('should render null as the empty string', inject(() { |
| 200 _.compile('<textarea ng-model="model">'); |
| 201 _.rootScope.$digest(); |
| 202 |
| 203 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); |
| 204 |
| 205 _.rootScope.$apply('model = null'); |
| 206 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); |
| 207 })); |
| 208 |
| 209 it('should update model from the input value', inject(() { |
| 210 _.compile('<textarea ng-model="model" probe="p">'); |
| 211 Probe probe = _.rootScope.p; |
| 212 var ngModel = probe.directive(NgModel); |
| 213 TextAreaElement element = probe.element; |
| 214 |
| 215 element.value = 'abc'; |
| 216 _.triggerEvent(element, 'change'); |
| 217 expect(_.rootScope.model).toEqual('abc'); |
| 218 |
| 219 element.value = 'def'; |
| 220 var textarea = probe.directive(InputTextLikeDirective); |
| 221 textarea.processValue(); |
| 222 expect(_.rootScope.model).toEqual('def'); |
| 223 |
| 224 })); |
| 225 |
| 226 // NOTE(deboer): This test passes on Dartium, but fails in the content_shell
. |
| 227 // The Dart team is looking into this bug. |
| 228 xit('should write to input only if value is different', inject(() { |
| 229 var scope = _.rootScope; |
| 230 var element = new dom.TextAreaElement(); |
| 231 var model = new NgModel(scope, new NodeAttrs(new DivElement()), element); |
| 232 dom.querySelector('body').append(element); |
| 233 var input = new InputTextLikeDirective(element, model, scope); |
| 234 |
| 235 element.value = 'abc'; |
| 236 element.selectionStart = 1; |
| 237 element.selectionEnd = 2; |
| 238 |
| 239 model.render('abc'); |
| 240 |
| 241 expect(element.value).toEqual('abc'); |
| 242 expect(element.selectionStart).toEqual(1); |
| 243 expect(element.selectionEnd).toEqual(2); |
| 244 |
| 245 model.render('xyz'); |
| 246 |
| 247 // Setting the value on a textarea doesn't update the selection the way it |
| 248 // does on input elements. This stays unchanged. |
| 249 expect(element.value).toEqual('xyz'); |
| 250 expect(element.selectionStart).toEqual(0); |
| 251 expect(element.selectionEnd).toEqual(0); |
| 252 })); |
| 253 }); |
| 254 |
| 255 describe('type="radio"', () { |
| 256 it('should update input value from model', inject(() { |
| 257 _.compile('<input type="radio" name="color" value="red" ng-model="color" p
robe="r">' + |
| 258 '<input type="radio" name="color" value="green" ng-model="color"
probe="g">' + |
| 259 '<input type="radio" name="color" value="blue" ng-model="color"
probe="b">'); |
| 260 _.rootScope.$digest(); |
| 261 |
| 262 RadioButtonInputElement redBtn = _.rootScope.r.element; |
| 263 RadioButtonInputElement greenBtn = _.rootScope.g.element; |
| 264 RadioButtonInputElement blueBtn = _.rootScope.b.element; |
| 265 |
| 266 expect(redBtn.checked).toBe(false); |
| 267 expect(greenBtn.checked).toBe(false); |
| 268 expect(blueBtn.checked).toBe(false); |
| 269 |
| 270 // Should change correct element to checked. |
| 271 _.rootScope.$apply('color = "green"'); |
| 272 |
| 273 expect(redBtn.checked).toBe(false); |
| 274 expect(greenBtn.checked).toBe(true); |
| 275 expect(blueBtn.checked).toBe(false); |
| 276 |
| 277 // Non-existing element. |
| 278 _.rootScope.$apply('color = "unknown"'); |
| 279 |
| 280 expect(redBtn.checked).toBe(false); |
| 281 expect(greenBtn.checked).toBe(false); |
| 282 expect(blueBtn.checked).toBe(false); |
| 283 |
| 284 // Should update model with value of checked element. |
| 285 _.triggerEvent(redBtn, 'click'); |
| 286 |
| 287 expect(_.rootScope['color']).toEqual('red'); |
| 288 expect(redBtn.checked).toBe(true); |
| 289 expect(greenBtn.checked).toBe(false); |
| 290 expect(blueBtn.checked).toBe(false); |
| 291 |
| 292 _.triggerEvent(greenBtn, 'click'); |
| 293 expect(_.rootScope['color']).toEqual('green'); |
| 294 expect(redBtn.checked).toBe(false); |
| 295 expect(greenBtn.checked).toBe(true); |
| 296 expect(blueBtn.checked).toBe(false); |
| 297 })); |
| 298 }); |
| 299 |
| 300 describe('contenteditable', () { |
| 301 it('should update content from model', inject(() { |
| 302 _.compile('<p contenteditable ng-model="model">'); |
| 303 _.rootScope.$digest(); |
| 304 |
| 305 expect(_.rootElement.text).toEqual(''); |
| 306 |
| 307 _.rootScope.$apply('model = "misko"'); |
| 308 expect(_.rootElement.text).toEqual('misko'); |
| 309 })); |
| 310 |
| 311 it('should update model from the input value', inject(() { |
| 312 _.compile('<p contenteditable ng-model="model">'); |
| 313 Element element = _.rootElement; |
| 314 |
| 315 element.innerHtml = 'abc'; |
| 316 _.triggerEvent(element, 'change'); |
| 317 expect(_.rootScope.model).toEqual('abc'); |
| 318 |
| 319 element.innerHtml = 'def'; |
| 320 var input = ngInjector(element).get(ContentEditableDirective); |
| 321 input.processValue(); |
| 322 expect(_.rootScope.model).toEqual('def'); |
| 323 })); |
| 324 }); |
| 325 |
| 326 describe('pristine / dirty', () { |
| 327 it('should be set to pristine by default', inject((Scope scope) { |
| 328 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
| 329 Probe probe = _.rootScope.i; |
| 330 var model = probe.directive(NgModel); |
| 331 |
| 332 expect(model.pristine).toEqual(true); |
| 333 expect(model.dirty).toEqual(false); |
| 334 })); |
| 335 |
| 336 it('should add and remove the correct CSS classes when set to dirty and to p
ristine', inject((Scope scope) { |
| 337 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
| 338 Probe probe = _.rootScope.i; |
| 339 var model = probe.directive(NgModel); |
| 340 InputElement element = probe.element; |
| 341 |
| 342 model.dirty = true; |
| 343 expect(model.pristine).toEqual(false); |
| 344 expect(model.dirty).toEqual(true); |
| 345 expect(element.classes.contains('ng-pristine')).toBe(false); |
| 346 expect(element.classes.contains('ng-dirty')).toBe(true); |
| 347 |
| 348 model.pristine = true; |
| 349 expect(model.pristine).toEqual(true); |
| 350 expect(model.dirty).toEqual(false); |
| 351 expect(element.classes.contains('ng-pristine')).toBe(true); |
| 352 expect(element.classes.contains('ng-dirty')).toBe(false); |
| 353 })); |
| 354 }); |
| 355 |
| 356 describe('valid / invalid', () { |
| 357 it('should add and remove the correct flags when set to valid and to invalid
', inject((Scope scope) { |
| 358 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
| 359 Probe probe = _.rootScope.i; |
| 360 var model = probe.directive(NgModel); |
| 361 InputElement element = probe.element; |
| 362 |
| 363 model.invalid = true; |
| 364 expect(model.valid).toEqual(false); |
| 365 expect(model.invalid).toEqual(true); |
| 366 expect(element.classes.contains('ng-valid')).toBe(false); |
| 367 expect(element.classes.contains('ng-invalid')).toBe(true); |
| 368 |
| 369 model.valid = true; |
| 370 expect(model.valid).toEqual(true); |
| 371 expect(model.invalid).toEqual(false); |
| 372 expect(element.classes.contains('ng-invalid')).toBe(false); |
| 373 expect(element.classes.contains('ng-valid')).toBe(true); |
| 374 })); |
| 375 |
| 376 it('should set the validity with respect to all existing validations when se
tValidity() is used', inject((Scope scope) { |
| 377 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
| 378 Probe probe = _.rootScope.i; |
| 379 var model = probe.directive(NgModel); |
| 380 |
| 381 model.setValidity("required", false); |
| 382 expect(model.valid).toEqual(false); |
| 383 expect(model.invalid).toEqual(true); |
| 384 |
| 385 model.setValidity("format", false); |
| 386 expect(model.valid).toEqual(false); |
| 387 expect(model.invalid).toEqual(true); |
| 388 |
| 389 model.setValidity("format", true); |
| 390 expect(model.valid).toEqual(false); |
| 391 expect(model.invalid).toEqual(true); |
| 392 |
| 393 model.setValidity("required", true); |
| 394 expect(model.valid).toEqual(true); |
| 395 expect(model.invalid).toEqual(false); |
| 396 })); |
| 397 |
| 398 it('should register each error only once when invalid', inject((Scope scope)
{ |
| 399 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
| 400 Probe probe = _.rootScope.i; |
| 401 var model = probe.directive(NgModel); |
| 402 |
| 403 model.setValidity("distinct-error", false); |
| 404 expect(model.valid).toEqual(false); |
| 405 expect(model.invalid).toEqual(true); |
| 406 |
| 407 model.setValidity("distinct-error", false); |
| 408 expect(model.valid).toEqual(false); |
| 409 expect(model.invalid).toEqual(true); |
| 410 |
| 411 model.setValidity("distinct-error", true); |
| 412 expect(model.valid).toEqual(true); |
| 413 expect(model.invalid).toEqual(false); |
| 414 })); |
| 415 }); |
| 416 |
| 417 }); |
| OLD | NEW |