| 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 main() => | 6 void main() { |
| 7 describe('ng-model', () { | 7 describe('ng-model', () { |
| 8 TestBed _; | 8 TestBed _; |
| 9 | 9 |
| 10 beforeEach(inject((TestBed tb) => _ = tb)); | 10 beforeEach(module((Module module) { |
| 11 | 11 module..type(ControllerWithNoLove); |
| 12 describe('type="text"', () { | |
| 13 it('should update input value from model', inject(() { | |
| 14 _.compile('<input type="text" ng-model="model">'); | |
| 15 _.rootScope.$digest(); | |
| 16 | |
| 17 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 18 | |
| 19 _.rootScope.$apply('model = "misko"'); | |
| 20 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | |
| 21 })); | 12 })); |
| 22 | 13 |
| 23 it('should render null as the empty string', inject(() { | 14 beforeEach(inject((TestBed tb) => _ = tb)); |
| 24 _.compile('<input type="text" ng-model="model">'); | 15 |
| 25 _.rootScope.$digest(); | 16 describe('type="text" like', () { |
| 26 | 17 it('should update input value from model', inject(() { |
| 27 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 18 _.compile('<input type="text" ng-model="model">'); |
| 28 | 19 _.rootScope.apply(); |
| 29 _.rootScope.$apply('model = null'); | 20 |
| 30 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 21 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 31 })); | 22 |
| 32 | 23 _.rootScope.apply('model = "misko"'); |
| 33 it('should update model from the input value', inject(() { | 24 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
| 34 _.compile('<input type="text" ng-model="model" probe="p">'); | 25 })); |
| 35 Probe probe = _.rootScope.p; | 26 |
| 36 var ngModel = probe.directive(NgModel); | 27 it('should render null as the empty string', inject(() { |
| 37 InputElement inputElement = probe.element; | 28 _.compile('<input type="text" ng-model="model">'); |
| 38 | 29 _.rootScope.apply(); |
| 39 inputElement.value = 'abc'; | 30 |
| 40 _.triggerEvent(inputElement, 'change'); | 31 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 41 expect(_.rootScope.model).toEqual('abc'); | 32 |
| 42 | 33 _.rootScope.apply('model = null'); |
| 43 inputElement.value = 'def'; | 34 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 44 var input = probe.directive(InputTextLikeDirective); | 35 })); |
| 45 input.processValue(); | 36 |
| 46 expect(_.rootScope.model).toEqual('def'); | 37 it('should update model from the input value', inject(() { |
| 47 })); | 38 _.compile('<input type="text" ng-model="model" probe="p">'); |
| 48 | 39 Probe probe = _.rootScope.context['p']; |
| 49 it('should write to input only if value is different', inject(() { | 40 var ngModel = probe.directive(NgModel); |
| 50 var scope = _.rootScope; | 41 InputElement inputElement = probe.element; |
| 51 var element = new dom.InputElement(); | 42 |
| 52 var model = new NgModel(scope, new NodeAttrs(new DivElement()), element, n
ew NgNullForm()); | 43 inputElement.value = 'abc'; |
| 53 dom.querySelector('body').append(element); | 44 _.triggerEvent(inputElement, 'change'); |
| 54 var input = new InputTextLikeDirective(element, model, scope); | 45 expect(_.rootScope.context['model']).toEqual('abc'); |
| 55 | 46 |
| 56 element.value = 'abc'; | 47 inputElement.value = 'def'; |
| 57 element.selectionStart = 1; | 48 var input = probe.directive(InputTextLikeDirective); |
| 58 element.selectionEnd = 2; | 49 input.processValue(); |
| 59 | 50 expect(_.rootScope.context['model']).toEqual('def'); |
| 60 model.render('abc'); | 51 })); |
| 61 | 52 |
| 62 expect(element.value).toEqual('abc'); | 53 it('should update model from the input value for type=number', inject(() { |
| 63 // No update. selectionStart/End is unchanged. | 54 _.compile('<input type="number" ng-model="model" probe="p">'); |
| 64 expect(element.selectionStart).toEqual(1); | 55 Probe probe = _.rootScope.context['p']; |
| 65 expect(element.selectionEnd).toEqual(2); | 56 var ngModel = probe.directive(NgModel); |
| 66 | 57 InputElement inputElement = probe.element; |
| 67 model.render('xyz'); | 58 |
| 68 | 59 inputElement.value = '12'; |
| 69 // Value updated. selectionStart/End changed. | 60 _.triggerEvent(inputElement, 'change'); |
| 70 expect(element.value).toEqual('xyz'); | 61 expect(_.rootScope.context['model']).toEqual(12); |
| 71 expect(element.selectionStart).toEqual(3); | 62 |
| 72 expect(element.selectionEnd).toEqual(3); | 63 inputElement.value = '14'; |
| 73 })); | 64 var input = probe.directive(InputNumberLikeDirective); |
| 65 input.processValue(); |
| 66 expect(_.rootScope.context['model']).toEqual(14); |
| 67 })); |
| 68 |
| 69 it('should update input type=number to blank when model is null', inject((
) { |
| 70 _.compile('<input type="number" ng-model="model" probe="p">'); |
| 71 Probe probe = _.rootScope.context['p']; |
| 72 var ngModel = probe.directive(NgModel); |
| 73 InputElement inputElement = probe.element; |
| 74 |
| 75 inputElement.value = '12'; |
| 76 _.triggerEvent(inputElement, 'change'); |
| 77 expect(_.rootScope.context['model']).toEqual(12); |
| 78 |
| 79 _.rootScope.context['model'] = null; |
| 80 _.rootScope.apply(); |
| 81 expect(inputElement.value).toEqual(''); |
| 82 })); |
| 83 |
| 84 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { |
| 85 var scope = _.rootScope; |
| 86 var element = new dom.InputElement(); |
| 87 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
| 88 nodeAttrs['ng-model'] = 'model'; |
| 89 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); |
| 90 dom.querySelector('body').append(element); |
| 91 var input = new InputTextLikeDirective(element, model, scope); |
| 92 |
| 93 element |
| 94 ..value = 'abc' |
| 95 ..selectionStart = 1 |
| 96 ..selectionEnd = 2; |
| 97 |
| 98 model.render('abc'); |
| 99 |
| 100 expect(element.value).toEqual('abc'); |
| 101 // No update. selectionStart/End is unchanged. |
| 102 expect(element.selectionStart).toEqual(1); |
| 103 expect(element.selectionEnd).toEqual(2); |
| 104 |
| 105 model.render('xyz'); |
| 106 |
| 107 // Value updated. selectionStart/End changed. |
| 108 expect(element.value).toEqual('xyz'); |
| 109 expect(element.selectionStart).toEqual(3); |
| 110 expect(element.selectionEnd).toEqual(3); |
| 111 })); |
| 112 }); |
| 113 |
| 114 /* This function simulates typing the given text into the input |
| 115 * field. The text will be added wherever the insertion point |
| 116 * happens to be. This method has as side-effect to set the |
| 117 * focus on the input (without setting the focus the text |
| 118 * dispatch may not work). |
| 119 */ |
| 120 void simulateTypingText(InputElement input, String text) { |
| 121 input..focus()..dispatchEvent(new TextEvent('textInput', data: text)); |
| 122 } |
| 123 |
| 124 describe('type="number" like', () { |
| 125 |
| 126 it('should leave input unchanged when text does not represent a valid numb
er', inject((Injector i) { |
| 127 var modelFieldName = 'modelForNumFromInvalid1'; |
| 128 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); |
| 129 dom.querySelector('body').append(element); |
| 130 |
| 131 // This test will progressively enter the text '1e1' |
| 132 // '1' is a valid number. |
| 133 // '1e' is not a valid number. |
| 134 // '1e1' is again a valid number (with an exponent) |
| 135 |
| 136 simulateTypingText(element, '1'); |
| 137 _.triggerEvent(element, 'change'); |
| 138 expect(element.value).toEqual('1'); |
| 139 expect(_.rootScope.context[modelFieldName]).toEqual(1); |
| 140 |
| 141 simulateTypingText(element, 'e'); |
| 142 // Because the text is not a valid number, the element value is empty. |
| 143 expect(element.value).toEqual(''); |
| 144 // When the input is invalid, the model is [double.NAN]: |
| 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 }); |
| 701 |
| 702 it('should render as dirty when checked', inject((Scope scope) { |
| 703 var element = _.compile( |
| 704 '<div>' + |
| 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 }); |
| 1001 }); |
| 1002 |
| 1003 describe('reset()', () { |
| 1004 it('should reset the model value to its original state', () { |
| 1005 _.compile('<input type="text" ng-model="myModel" probe="i" />'); |
| 1006 _.rootScope.apply('myModel = "animal"'); |
| 1007 |
| 1008 Probe probe = _.rootScope.context['i']; |
| 1009 var model = probe.directive(NgModel); |
| 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 }); |
| 1027 }); |
| 1028 |
| 1029 it('should set the model to be untouched when the model is reset', () { |
| 1030 var input = _.compile('<input type="text" ng-model="myModel" probe="i" />'
); |
| 1031 var model = _.rootScope.context['i'].directive(NgModel); |
| 1032 |
| 1033 expect(model.touched).toBe(false); |
| 1034 expect(model.untouched).toBe(true); |
| 1035 |
| 1036 _.triggerEvent(input, 'blur'); |
| 1037 |
| 1038 expect(model.touched).toBe(true); |
| 1039 expect(model.untouched).toBe(false); |
| 1040 |
| 1041 model.reset(); |
| 1042 |
| 1043 expect(model.touched).toBe(false); |
| 1044 expect(model.untouched).toBe(true); |
| 1045 }); |
| 74 }); | 1046 }); |
| 75 | 1047 } |
| 76 describe('type="password"', () { | 1048 |
| 77 it('should update input value from model', inject(() { | 1049 @NgController( |
| 78 _.compile('<input type="password" ng-model="model">'); | 1050 selector: '[no-love]', |
| 79 _.rootScope.$digest(); | 1051 publishAs: 'ctrl') |
| 80 | 1052 class ControllerWithNoLove { |
| 81 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 1053 var apathy = null; |
| 82 | 1054 } |
| 83 _.rootScope.$apply('model = "misko"'); | |
| 84 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | |
| 85 })); | |
| 86 | |
| 87 it('should render null as the empty string', inject(() { | |
| 88 _.compile('<input type="password" ng-model="model">'); | |
| 89 _.rootScope.$digest(); | |
| 90 | |
| 91 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 92 | |
| 93 _.rootScope.$apply('model = null'); | |
| 94 expect((_.rootElement as dom.InputElement).value).toEqual(''); | |
| 95 })); | |
| 96 | |
| 97 it('should update model from the input value', inject(() { | |
| 98 _.compile('<input type="password" ng-model="model" probe="p">'); | |
| 99 Probe probe = _.rootScope.p; | |
| 100 var ngModel = probe.directive(NgModel); | |
| 101 InputElement inputElement = probe.element; | |
| 102 | |
| 103 inputElement.value = 'abc'; | |
| 104 _.triggerEvent(inputElement, 'change'); | |
| 105 expect(_.rootScope.model).toEqual('abc'); | |
| 106 | |
| 107 inputElement.value = 'def'; | |
| 108 var input = probe.directive(InputTextLikeDirective); | |
| 109 input.processValue(); | |
| 110 expect(_.rootScope.model).toEqual('def'); | |
| 111 | |
| 112 })); | |
| 113 | |
| 114 it('should write to input only if value is different', inject(() { | |
| 115 var scope = _.rootScope; | |
| 116 var element = new dom.InputElement(); | |
| 117 var model = new NgModel(scope, new NodeAttrs(new DivElement()), element, n
ew NgNullForm()); | |
| 118 dom.querySelector('body').append(element); | |
| 119 var input = new InputTextLikeDirective(element, model, scope); | |
| 120 | |
| 121 element.value = 'abc'; | |
| 122 element.selectionStart = 1; | |
| 123 element.selectionEnd = 2; | |
| 124 | |
| 125 model.render('abc'); | |
| 126 | |
| 127 expect(element.value).toEqual('abc'); | |
| 128 expect(element.selectionStart).toEqual(1); | |
| 129 expect(element.selectionEnd).toEqual(2); | |
| 130 | |
| 131 model.render('xyz'); | |
| 132 | |
| 133 expect(element.value).toEqual('xyz'); | |
| 134 expect(element.selectionStart).toEqual(3); | |
| 135 expect(element.selectionEnd).toEqual(3); | |
| 136 })); | |
| 137 }); | |
| 138 | |
| 139 describe('type="checkbox"', () { | |
| 140 it('should update input value from model', inject((Scope scope) { | |
| 141 var element = _.compile('<input type="checkbox" ng-model="model">'); | |
| 142 | |
| 143 scope.$apply(() { | |
| 144 scope['model'] = true; | |
| 145 }); | |
| 146 expect(element.checked).toBe(true); | |
| 147 | |
| 148 scope.$apply(() { | |
| 149 scope['model'] = false; | |
| 150 }); | |
| 151 expect(element.checked).toBe(false); | |
| 152 })); | |
| 153 | |
| 154 | |
| 155 it('should allow non boolean values like null, 0, 1', inject((Scope scope) { | |
| 156 var element = _.compile('<input type="checkbox" ng-model="model">'); | |
| 157 | |
| 158 scope.$apply(() { | |
| 159 scope['model'] = 0; | |
| 160 }); | |
| 161 expect(element.checked).toBe(false); | |
| 162 | |
| 163 scope.$apply(() { | |
| 164 scope['model'] = 1; | |
| 165 }); | |
| 166 expect(element.checked).toBe(true); | |
| 167 | |
| 168 scope.$apply(() { | |
| 169 scope['model'] = null; | |
| 170 }); | |
| 171 expect(element.checked).toBe(false); | |
| 172 })); | |
| 173 | |
| 174 | |
| 175 it('should update model from the input value', inject((Scope scope) { | |
| 176 var element = _.compile('<input type="checkbox" ng-model="model">'); | |
| 177 | |
| 178 element.checked = true; | |
| 179 _.triggerEvent(element, 'change'); | |
| 180 expect(scope['model']).toBe(true); | |
| 181 | |
| 182 element.checked = false; | |
| 183 _.triggerEvent(element, 'change'); | |
| 184 expect(scope['model']).toBe(false); | |
| 185 })); | |
| 186 }); | |
| 187 | |
| 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 |