| 
									
										
										
										
											2016-06-23 09:47:54 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-23 20:53:29 +03:00
										 |  |  | import {SimpleChange} from '@angular/core'; | 
					
						
							| 
									
										
										
										
											2016-08-02 15:53:34 -07:00
										 |  |  | import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; | 
					
						
							| 
									
										
										
										
											2017-03-02 12:12:46 -08:00
										 |  |  | import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal'; | 
					
						
							| 
									
										
										
										
											2017-02-23 20:53:29 +03:00
										 |  |  | import {AbstractControl, CheckboxControlValueAccessor, ControlValueAccessor, DefaultValueAccessor, FormArray, FormArrayName, FormControl, FormControlDirective, FormControlName, FormGroup, FormGroupDirective, FormGroupName, NgControl, NgForm, NgModel, NgModelGroup, SelectControlValueAccessor, SelectMultipleControlValueAccessor, ValidationErrors, Validator, Validators} from '@angular/forms'; | 
					
						
							|  |  |  | import {composeValidators, selectValueAccessor} from '../src/directives/shared'; | 
					
						
							| 
									
										
										
										
											2016-06-14 18:23:40 -07:00
										 |  |  | import {SpyNgControl, SpyValueAccessor} from './spies'; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class DummyControlValueAccessor implements ControlValueAccessor { | 
					
						
							| 
									
										
										
										
											2016-06-11 21:23:37 -07:00
										 |  |  |   writtenValue: any; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-23 20:53:29 +03:00
										 |  |  |   registerOnChange(fn: any) {} | 
					
						
							|  |  |  |   registerOnTouched(fn: any) {} | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   writeValue(obj: any): void { this.writtenValue = obj; } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CustomValidatorDirective implements Validator { | 
					
						
							| 
									
										
										
										
											2017-02-23 20:53:29 +03:00
										 |  |  |   validate(c: FormControl): ValidationErrors { return {'custom': true}; } | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-23 20:53:29 +03:00
										 |  |  | function asyncValidator(expected: any, timeout = 0) { | 
					
						
							|  |  |  |   return (c: AbstractControl): any => { | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |     let resolve: (result: any) => void = undefined !; | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |     const promise = new Promise(res => { resolve = res; }); | 
					
						
							|  |  |  |     const res = c.value != expected ? {'async': true} : null; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     if (timeout == 0) { | 
					
						
							| 
									
										
										
										
											2016-08-02 15:53:34 -07:00
										 |  |  |       resolve(res); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2016-08-02 15:53:34 -07:00
										 |  |  |       setTimeout(() => { resolve(res); }, timeout); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-08-02 15:53:34 -07:00
										 |  |  |     return promise; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function main() { | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |   describe('Form Directives', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |     let defaultAccessor: DefaultValueAccessor; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |     beforeEach(() => { defaultAccessor = new DefaultValueAccessor(null !, null !, null !); }); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |     describe('shared', () => { | 
					
						
							|  |  |  |       describe('selectValueAccessor', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |         let dir: NgControl; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         beforeEach(() => { dir = <any>new SpyNgControl(); }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should throw when given an empty array', | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |            () => { expect(() => selectValueAccessor(dir, [])).toThrowError(); }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should return the default value accessor when no other provided', | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |            () => { expect(selectValueAccessor(dir, [defaultAccessor])).toEqual(defaultAccessor); }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should return checkbox accessor when provided', () => { | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const checkboxAccessor = new CheckboxControlValueAccessor(null !, null !); | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |           expect(selectValueAccessor(dir, [ | 
					
						
							|  |  |  |             defaultAccessor, checkboxAccessor | 
					
						
							|  |  |  |           ])).toEqual(checkboxAccessor); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should return select accessor when provided', () => { | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const selectAccessor = new SelectControlValueAccessor(null !, null !); | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |           expect(selectValueAccessor(dir, [ | 
					
						
							|  |  |  |             defaultAccessor, selectAccessor | 
					
						
							|  |  |  |           ])).toEqual(selectAccessor); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-30 18:04:00 -07:00
										 |  |  |         it('should return select multiple accessor when provided', () => { | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const selectMultipleAccessor = new SelectMultipleControlValueAccessor(null !, null !); | 
					
						
							| 
									
										
										
										
											2016-06-30 18:04:00 -07:00
										 |  |  |           expect(selectValueAccessor(dir, [ | 
					
						
							|  |  |  |             defaultAccessor, selectMultipleAccessor | 
					
						
							|  |  |  |           ])).toEqual(selectMultipleAccessor); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should throw when more than one build-in accessor is provided', () => { | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const checkboxAccessor = new CheckboxControlValueAccessor(null !, null !); | 
					
						
							|  |  |  |           const selectAccessor = new SelectControlValueAccessor(null !, null !); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |           expect(() => selectValueAccessor(dir, [checkboxAccessor, selectAccessor])).toThrowError(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should return custom accessor when provided', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |           const customAccessor = new SpyValueAccessor(); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const checkboxAccessor = new CheckboxControlValueAccessor(null !, null !); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |           expect(selectValueAccessor(dir, <any>[defaultAccessor, customAccessor, checkboxAccessor])) | 
					
						
							|  |  |  |               .toEqual(customAccessor); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-30 18:04:00 -07:00
										 |  |  |         it('should return custom accessor when provided with select multiple', () => { | 
					
						
							|  |  |  |           const customAccessor = new SpyValueAccessor(); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const selectMultipleAccessor = new SelectMultipleControlValueAccessor(null !, null !); | 
					
						
							| 
									
										
										
										
											2016-06-30 18:04:00 -07:00
										 |  |  |           expect(selectValueAccessor( | 
					
						
							|  |  |  |                      dir, <any>[defaultAccessor, customAccessor, selectMultipleAccessor])) | 
					
						
							|  |  |  |               .toEqual(customAccessor); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should throw when more than one custom accessor is provided', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |           const customAccessor: ControlValueAccessor = <any>new SpyValueAccessor(); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |           expect(() => selectValueAccessor(dir, [customAccessor, customAccessor])).toThrowError(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       describe('composeValidators', () => { | 
					
						
							|  |  |  |         it('should compose functions', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |           const dummy1 = (_: any /** TODO #9100 */) => ({'dummy1': true}); | 
					
						
							|  |  |  |           const dummy2 = (_: any /** TODO #9100 */) => ({'dummy2': true}); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const v = composeValidators([dummy1, dummy2]) !; | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |           expect(v(new FormControl(''))).toEqual({'dummy1': true, 'dummy2': true}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should compose validator directives', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |           const dummy1 = (_: any /** TODO #9100 */) => ({'dummy1': true}); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const v = composeValidators([dummy1, new CustomValidatorDirective()]) !; | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |           expect(v(new FormControl(''))).toEqual({'dummy1': true, 'custom': true}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-10 19:10:17 -07:00
										 |  |  |     describe('formGroup', () => { | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  |       let form: FormGroupDirective; | 
					
						
							|  |  |  |       let formModel: FormGroup; | 
					
						
							|  |  |  |       let loginControlDir: FormControlName; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2016-06-10 19:10:17 -07:00
										 |  |  |         form = new FormGroupDirective([], []); | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |         formModel = new FormGroup({ | 
					
						
							|  |  |  |           'login': new FormControl(), | 
					
						
							|  |  |  |           'passwords': new FormGroup( | 
					
						
							|  |  |  |               {'password': new FormControl(), 'passwordConfirm': new FormControl()}) | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  |         form.form = formModel; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-12 13:17:07 -07:00
										 |  |  |         loginControlDir = new FormControlName( | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |             form, [Validators.required], [asyncValidator('expected')], [defaultAccessor]); | 
					
						
							|  |  |  |         loginControlDir.name = 'login'; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         loginControlDir.valueAccessor = new DummyControlValueAccessor(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should reexport control properties', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(form.control).toBe(formModel); | 
					
						
							|  |  |  |         expect(form.value).toBe(formModel.value); | 
					
						
							|  |  |  |         expect(form.valid).toBe(formModel.valid); | 
					
						
							| 
									
										
										
										
											2016-08-01 18:41:25 -07:00
										 |  |  |         expect(form.invalid).toBe(formModel.invalid); | 
					
						
							|  |  |  |         expect(form.pending).toBe(formModel.pending); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(form.errors).toBe(formModel.errors); | 
					
						
							|  |  |  |         expect(form.pristine).toBe(formModel.pristine); | 
					
						
							|  |  |  |         expect(form.dirty).toBe(formModel.dirty); | 
					
						
							|  |  |  |         expect(form.touched).toBe(formModel.touched); | 
					
						
							|  |  |  |         expect(form.untouched).toBe(formModel.untouched); | 
					
						
							| 
									
										
										
										
											2016-06-24 13:37:42 -07:00
										 |  |  |         expect(form.statusChanges).toBe(formModel.statusChanges); | 
					
						
							|  |  |  |         expect(form.valueChanges).toBe(formModel.valueChanges); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:49:02 +02:00
										 |  |  |       it('should reexport control methods', () => { | 
					
						
							|  |  |  |         expect(form.hasError('required')).toBe(formModel.hasError('required')); | 
					
						
							|  |  |  |         expect(form.getError('required')).toBe(formModel.getError('required')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         formModel.setErrors({required: true}); | 
					
						
							|  |  |  |         expect(form.hasError('required')).toBe(formModel.hasError('required')); | 
					
						
							|  |  |  |         expect(form.getError('required')).toBe(formModel.getError('required')); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       describe('addControl', () => { | 
					
						
							|  |  |  |         it('should throw when no control found', () => { | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const dir = new FormControlName(form, null !, null !, [defaultAccessor]); | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |           dir.name = 'invalidName'; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |           expect(() => form.addControl(dir)) | 
					
						
							| 
									
										
										
										
											2016-07-13 14:13:02 -07:00
										 |  |  |               .toThrowError(new RegExp(`Cannot find control with name: 'invalidName'`)); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 14:13:02 -07:00
										 |  |  |         it('should throw for a named control when no value accessor', () => { | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const dir = new FormControlName(form, null !, null !, null !); | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |           dir.name = 'login'; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |           expect(() => form.addControl(dir)) | 
					
						
							| 
									
										
										
										
											2016-07-13 14:13:02 -07:00
										 |  |  |               .toThrowError(new RegExp(`No value accessor for form control with name: 'login'`)); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should throw when no value accessor with path', () => { | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |           const group = new FormGroupName(form, null !, null !); | 
					
						
							|  |  |  |           const dir = new FormControlName(group, null !, null !, null !); | 
					
						
							| 
									
										
										
										
											2016-07-13 14:13:02 -07:00
										 |  |  |           group.name = 'passwords'; | 
					
						
							|  |  |  |           dir.name = 'password'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           expect(() => form.addControl(dir)) | 
					
						
							|  |  |  |               .toThrowError(new RegExp( | 
					
						
							|  |  |  |                   `No value accessor for form control with path: 'passwords -> password'`)); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should set up validators', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |              form.addControl(loginControlDir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // sync validators are set
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |              expect(formModel.hasError('required', ['login'])).toBe(true); | 
					
						
							|  |  |  |              expect(formModel.hasError('async', ['login'])).toBe(false); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 13:35:17 -07:00
										 |  |  |              (<FormControl>formModel.get('login')).setValue('invalid value'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |              // sync validator passes, running async validators
 | 
					
						
							|  |  |  |              expect(formModel.pending).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |              expect(formModel.hasError('required', ['login'])).toBe(false); | 
					
						
							|  |  |  |              expect(formModel.hasError('async', ['login'])).toBe(true); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should write value to the DOM', () => { | 
					
						
							| 
									
										
										
										
											2016-08-05 13:35:17 -07:00
										 |  |  |           (<FormControl>formModel.get(['login'])).setValue('initValue'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |           form.addControl(loginControlDir); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |           expect((<any>loginControlDir.valueAccessor).writtenValue).toEqual('initValue'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should add the directive to the list of directives included in the form', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |           form.addControl(loginControlDir); | 
					
						
							|  |  |  |           expect(form.directives).toEqual([loginControlDir]); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |       describe('addFormGroup', () => { | 
					
						
							| 
									
										
										
										
											2017-02-23 20:53:29 +03:00
										 |  |  |         const matchingPasswordsValidator = (g: FormGroup) => { | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |           if (g.controls['password'].value != g.controls['passwordConfirm'].value) { | 
					
						
							|  |  |  |             return {'differentPasswords': true}; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |           } else { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should set up validator', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |              const group = new FormGroupName( | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |                  form, [matchingPasswordsValidator], [asyncValidator('expected')]); | 
					
						
							|  |  |  |              group.name = 'passwords'; | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |              form.addFormGroup(group); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 13:35:17 -07:00
										 |  |  |              (<FormControl>formModel.get(['passwords', 'password'])).setValue('somePassword'); | 
					
						
							|  |  |  |              (<FormControl>formModel.get([ | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |                'passwords', 'passwordConfirm' | 
					
						
							| 
									
										
										
										
											2016-08-05 13:35:17 -07:00
										 |  |  |              ])).setValue('someOtherPassword'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |              // sync validators are set
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |              expect(formModel.hasError('differentPasswords', ['passwords'])).toEqual(true); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 13:35:17 -07:00
										 |  |  |              (<FormControl>formModel.get([ | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |                'passwords', 'passwordConfirm' | 
					
						
							| 
									
										
										
										
											2016-08-05 13:35:17 -07:00
										 |  |  |              ])).setValue('somePassword'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |              // sync validators pass, running async validators
 | 
					
						
							|  |  |  |              expect(formModel.pending).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |              expect(formModel.hasError('async', ['passwords'])).toBe(true); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |            })); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       describe('removeControl', () => { | 
					
						
							|  |  |  |         it('should remove the directive to the list of directives included in the form', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |           form.addControl(loginControlDir); | 
					
						
							|  |  |  |           form.removeControl(loginControlDir); | 
					
						
							|  |  |  |           expect(form.directives).toEqual([]); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       describe('ngOnChanges', () => { | 
					
						
							|  |  |  |         it('should update dom values of all the directives', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |           form.addControl(loginControlDir); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 13:35:17 -07:00
										 |  |  |           (<FormControl>formModel.get(['login'])).setValue('new value'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |           form.ngOnChanges({}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |           expect((<any>loginControlDir.valueAccessor).writtenValue).toEqual('new value'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should set up a sync validator', () => { | 
					
						
							| 
									
										
										
										
											2017-02-23 20:53:29 +03:00
										 |  |  |           const formValidator = (c: AbstractControl) => ({'custom': true}); | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |           const f = new FormGroupDirective([formValidator], []); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |           f.form = formModel; | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |           f.ngOnChanges({'form': new SimpleChange(null, null, false)}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |           expect(formModel.errors).toEqual({'custom': true}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should set up an async validator', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |              const f = new FormGroupDirective([], [asyncValidator('expected')]); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |              f.form = formModel; | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |              f.ngOnChanges({'form': new SimpleChange(null, null, false)}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |              expect(formModel.errors).toEqual({'async': true}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |            })); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |     describe('NgForm', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |       let form: any /** TODO #9100 */; | 
					
						
							|  |  |  |       let formModel: FormGroup; | 
					
						
							|  |  |  |       let loginControlDir: any /** TODO #9100 */; | 
					
						
							|  |  |  |       let personControlGroupDir: any /** TODO #9100 */; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							|  |  |  |         form = new NgForm([], []); | 
					
						
							|  |  |  |         formModel = form.form; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-12 16:37:42 -07:00
										 |  |  |         personControlGroupDir = new NgModelGroup(form, [], []); | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         personControlGroupDir.name = 'person'; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |         loginControlDir = new NgModel(personControlGroupDir, null !, null !, [defaultAccessor]); | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         loginControlDir.name = 'login'; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         loginControlDir.valueAccessor = new DummyControlValueAccessor(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should reexport control properties', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(form.control).toBe(formModel); | 
					
						
							|  |  |  |         expect(form.value).toBe(formModel.value); | 
					
						
							|  |  |  |         expect(form.valid).toBe(formModel.valid); | 
					
						
							| 
									
										
										
										
											2016-08-01 18:41:25 -07:00
										 |  |  |         expect(form.invalid).toBe(formModel.invalid); | 
					
						
							|  |  |  |         expect(form.pending).toBe(formModel.pending); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(form.errors).toBe(formModel.errors); | 
					
						
							|  |  |  |         expect(form.pristine).toBe(formModel.pristine); | 
					
						
							|  |  |  |         expect(form.dirty).toBe(formModel.dirty); | 
					
						
							|  |  |  |         expect(form.touched).toBe(formModel.touched); | 
					
						
							|  |  |  |         expect(form.untouched).toBe(formModel.untouched); | 
					
						
							| 
									
										
										
										
											2016-06-24 13:37:42 -07:00
										 |  |  |         expect(form.statusChanges).toBe(formModel.statusChanges); | 
					
						
							|  |  |  |         expect(form.valueChanges).toBe(formModel.valueChanges); | 
					
						
							| 
									
										
										
										
											2016-08-25 14:56:31 -07:00
										 |  |  |         expect(form.disabled).toBe(formModel.disabled); | 
					
						
							|  |  |  |         expect(form.enabled).toBe(formModel.enabled); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:49:02 +02:00
										 |  |  |       it('should reexport control methods', () => { | 
					
						
							|  |  |  |         expect(form.hasError('required')).toBe(formModel.hasError('required')); | 
					
						
							|  |  |  |         expect(form.getError('required')).toBe(formModel.getError('required')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         formModel.setErrors({required: true}); | 
					
						
							|  |  |  |         expect(form.hasError('required')).toBe(formModel.hasError('required')); | 
					
						
							|  |  |  |         expect(form.getError('required')).toBe(formModel.getError('required')); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |       describe('addControl & addFormGroup', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should create a control with the given name', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |              form.addFormGroup(personControlGroupDir); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |              form.addControl(loginControlDir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              flushMicrotasks(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 13:35:17 -07:00
										 |  |  |              expect(formModel.get(['person', 'login'])).not.toBeNull; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // should update the form's value and validity
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |       describe('removeControl & removeFormGroup', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         it('should remove control', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |              form.addFormGroup(personControlGroupDir); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |              form.addControl(loginControlDir); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |              form.removeFormGroup(personControlGroupDir); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |              form.removeControl(loginControlDir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              flushMicrotasks(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 13:35:17 -07:00
										 |  |  |              expect(formModel.get(['person'])).toBeNull(); | 
					
						
							|  |  |  |              expect(formModel.get(['person', 'login'])).toBeNull(); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // should update the form's value and validity
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should set up sync validator', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |            const formValidator = (c: any /** TODO #9100 */) => ({'custom': true}); | 
					
						
							|  |  |  |            const f = new NgForm([formValidator], []); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |            expect(f.form.errors).toEqual({'custom': true}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should set up async validator', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |            const f = new NgForm([], [asyncValidator('expected')]); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |            expect(f.form.errors).toEqual({'async': true}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |          })); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-12 16:37:42 -07:00
										 |  |  |     describe('FormGroupName', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |       let formModel: any /** TODO #9100 */; | 
					
						
							|  |  |  |       let controlGroupDir: any /** TODO #9100 */; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |         formModel = new FormGroup({'login': new FormControl(null)}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |         const parent = new FormGroupDirective([], []); | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |         parent.form = new FormGroup({'group': formModel}); | 
					
						
							| 
									
										
										
										
											2016-06-12 16:37:42 -07:00
										 |  |  |         controlGroupDir = new FormGroupName(parent, [], []); | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         controlGroupDir.name = 'group'; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should reexport control properties', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(controlGroupDir.control).toBe(formModel); | 
					
						
							|  |  |  |         expect(controlGroupDir.value).toBe(formModel.value); | 
					
						
							|  |  |  |         expect(controlGroupDir.valid).toBe(formModel.valid); | 
					
						
							| 
									
										
										
										
											2016-08-01 18:41:25 -07:00
										 |  |  |         expect(controlGroupDir.invalid).toBe(formModel.invalid); | 
					
						
							|  |  |  |         expect(controlGroupDir.pending).toBe(formModel.pending); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(controlGroupDir.errors).toBe(formModel.errors); | 
					
						
							|  |  |  |         expect(controlGroupDir.pristine).toBe(formModel.pristine); | 
					
						
							|  |  |  |         expect(controlGroupDir.dirty).toBe(formModel.dirty); | 
					
						
							|  |  |  |         expect(controlGroupDir.touched).toBe(formModel.touched); | 
					
						
							|  |  |  |         expect(controlGroupDir.untouched).toBe(formModel.untouched); | 
					
						
							| 
									
										
										
										
											2016-06-24 13:37:42 -07:00
										 |  |  |         expect(controlGroupDir.statusChanges).toBe(formModel.statusChanges); | 
					
						
							|  |  |  |         expect(controlGroupDir.valueChanges).toBe(formModel.valueChanges); | 
					
						
							| 
									
										
										
										
											2016-08-25 14:56:31 -07:00
										 |  |  |         expect(controlGroupDir.disabled).toBe(formModel.disabled); | 
					
						
							|  |  |  |         expect(controlGroupDir.enabled).toBe(formModel.enabled); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-10-19 18:49:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should reexport control methods', () => { | 
					
						
							|  |  |  |         expect(controlGroupDir.hasError('required')).toBe(formModel.hasError('required')); | 
					
						
							|  |  |  |         expect(controlGroupDir.getError('required')).toBe(formModel.getError('required')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         formModel.setErrors({required: true}); | 
					
						
							|  |  |  |         expect(controlGroupDir.hasError('required')).toBe(formModel.hasError('required')); | 
					
						
							|  |  |  |         expect(controlGroupDir.getError('required')).toBe(formModel.getError('required')); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-25 13:27:29 -07:00
										 |  |  |     describe('FormArrayName', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |       let formModel: FormArray; | 
					
						
							|  |  |  |       let formArrayDir: FormArrayName; | 
					
						
							| 
									
										
										
										
											2016-06-25 13:27:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							|  |  |  |         const parent = new FormGroupDirective([], []); | 
					
						
							|  |  |  |         formModel = new FormArray([new FormControl('')]); | 
					
						
							|  |  |  |         parent.form = new FormGroup({'array': formModel}); | 
					
						
							|  |  |  |         formArrayDir = new FormArrayName(parent, [], []); | 
					
						
							|  |  |  |         formArrayDir.name = 'array'; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should reexport control properties', () => { | 
					
						
							|  |  |  |         expect(formArrayDir.control).toBe(formModel); | 
					
						
							|  |  |  |         expect(formArrayDir.value).toBe(formModel.value); | 
					
						
							|  |  |  |         expect(formArrayDir.valid).toBe(formModel.valid); | 
					
						
							| 
									
										
										
										
											2016-08-01 18:41:25 -07:00
										 |  |  |         expect(formArrayDir.invalid).toBe(formModel.invalid); | 
					
						
							|  |  |  |         expect(formArrayDir.pending).toBe(formModel.pending); | 
					
						
							| 
									
										
										
										
											2016-06-25 13:27:29 -07:00
										 |  |  |         expect(formArrayDir.errors).toBe(formModel.errors); | 
					
						
							|  |  |  |         expect(formArrayDir.pristine).toBe(formModel.pristine); | 
					
						
							|  |  |  |         expect(formArrayDir.dirty).toBe(formModel.dirty); | 
					
						
							|  |  |  |         expect(formArrayDir.touched).toBe(formModel.touched); | 
					
						
							|  |  |  |         expect(formArrayDir.untouched).toBe(formModel.untouched); | 
					
						
							| 
									
										
										
										
											2016-08-25 14:56:31 -07:00
										 |  |  |         expect(formArrayDir.disabled).toBe(formModel.disabled); | 
					
						
							|  |  |  |         expect(formArrayDir.enabled).toBe(formModel.enabled); | 
					
						
							| 
									
										
										
										
											2016-06-25 13:27:29 -07:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-10-19 18:49:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should reexport control methods', () => { | 
					
						
							|  |  |  |         expect(formArrayDir.hasError('required')).toBe(formModel.hasError('required')); | 
					
						
							|  |  |  |         expect(formArrayDir.getError('required')).toBe(formModel.getError('required')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         formModel.setErrors({required: true}); | 
					
						
							|  |  |  |         expect(formArrayDir.hasError('required')).toBe(formModel.hasError('required')); | 
					
						
							|  |  |  |         expect(formArrayDir.getError('required')).toBe(formModel.getError('required')); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-06-25 13:27:29 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-10 17:28:19 -07:00
										 |  |  |     describe('FormControlDirective', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |       let controlDir: any /** TODO #9100 */; | 
					
						
							|  |  |  |       let control: any /** TODO #9100 */; | 
					
						
							| 
									
										
										
										
											2017-02-23 20:53:29 +03:00
										 |  |  |       const checkProperties = function(control: AbstractControl) { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(controlDir.control).toBe(control); | 
					
						
							|  |  |  |         expect(controlDir.value).toBe(control.value); | 
					
						
							|  |  |  |         expect(controlDir.valid).toBe(control.valid); | 
					
						
							| 
									
										
										
										
											2016-08-01 18:41:25 -07:00
										 |  |  |         expect(controlDir.invalid).toBe(control.invalid); | 
					
						
							|  |  |  |         expect(controlDir.pending).toBe(control.pending); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(controlDir.errors).toBe(control.errors); | 
					
						
							|  |  |  |         expect(controlDir.pristine).toBe(control.pristine); | 
					
						
							|  |  |  |         expect(controlDir.dirty).toBe(control.dirty); | 
					
						
							|  |  |  |         expect(controlDir.touched).toBe(control.touched); | 
					
						
							|  |  |  |         expect(controlDir.untouched).toBe(control.untouched); | 
					
						
							| 
									
										
										
										
											2016-06-24 13:37:42 -07:00
										 |  |  |         expect(controlDir.statusChanges).toBe(control.statusChanges); | 
					
						
							|  |  |  |         expect(controlDir.valueChanges).toBe(control.valueChanges); | 
					
						
							| 
									
										
										
										
											2016-08-25 14:56:31 -07:00
										 |  |  |         expect(controlDir.disabled).toBe(control.disabled); | 
					
						
							|  |  |  |         expect(controlDir.enabled).toBe(control.enabled); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2016-06-10 17:28:19 -07:00
										 |  |  |         controlDir = new FormControlDirective([Validators.required], [], [defaultAccessor]); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         controlDir.valueAccessor = new DummyControlValueAccessor(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |         control = new FormControl(null); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         controlDir.form = control; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should reexport control properties', () => { checkProperties(control); }); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:49:02 +02:00
										 |  |  |       it('should reexport control methods', () => { | 
					
						
							|  |  |  |         expect(controlDir.hasError('required')).toBe(control.hasError('required')); | 
					
						
							|  |  |  |         expect(controlDir.getError('required')).toBe(control.getError('required')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         control.setErrors({required: true}); | 
					
						
							|  |  |  |         expect(controlDir.hasError('required')).toBe(control.hasError('required')); | 
					
						
							|  |  |  |         expect(controlDir.getError('required')).toBe(control.getError('required')); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should reexport new control properties', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |         const newControl = new FormControl(null); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         controlDir.form = newControl; | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |         controlDir.ngOnChanges({'form': new SimpleChange(control, newControl, false)}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         checkProperties(newControl); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should set up validator', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(control.valid).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // this will add the required validator and recalculate the validity
 | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |         controlDir.ngOnChanges({'form': new SimpleChange(null, control, false)}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         expect(control.valid).toBe(false); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |     describe('NgModel', () => { | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |       let ngModel: NgModel; | 
					
						
							| 
									
										
										
										
											2016-10-19 18:49:02 +02:00
										 |  |  |       let control: FormControl; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2016-06-10 10:09:50 -07:00
										 |  |  |         ngModel = new NgModel( | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |             null !, [Validators.required], [asyncValidator('expected')], [defaultAccessor]); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         ngModel.valueAccessor = new DummyControlValueAccessor(); | 
					
						
							| 
									
										
										
										
											2016-10-19 18:49:02 +02:00
										 |  |  |         control = ngModel.control; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should reexport control properties', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(ngModel.control).toBe(control); | 
					
						
							|  |  |  |         expect(ngModel.value).toBe(control.value); | 
					
						
							|  |  |  |         expect(ngModel.valid).toBe(control.valid); | 
					
						
							| 
									
										
										
										
											2016-08-01 18:41:25 -07:00
										 |  |  |         expect(ngModel.invalid).toBe(control.invalid); | 
					
						
							|  |  |  |         expect(ngModel.pending).toBe(control.pending); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(ngModel.errors).toBe(control.errors); | 
					
						
							|  |  |  |         expect(ngModel.pristine).toBe(control.pristine); | 
					
						
							|  |  |  |         expect(ngModel.dirty).toBe(control.dirty); | 
					
						
							|  |  |  |         expect(ngModel.touched).toBe(control.touched); | 
					
						
							|  |  |  |         expect(ngModel.untouched).toBe(control.untouched); | 
					
						
							| 
									
										
										
										
											2016-06-24 13:37:42 -07:00
										 |  |  |         expect(ngModel.statusChanges).toBe(control.statusChanges); | 
					
						
							|  |  |  |         expect(ngModel.valueChanges).toBe(control.valueChanges); | 
					
						
							| 
									
										
										
										
											2016-08-25 14:56:31 -07:00
										 |  |  |         expect(ngModel.disabled).toBe(control.disabled); | 
					
						
							|  |  |  |         expect(ngModel.enabled).toBe(control.enabled); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:49:02 +02:00
										 |  |  |       it('should reexport control methods', () => { | 
					
						
							|  |  |  |         expect(ngModel.hasError('required')).toBe(control.hasError('required')); | 
					
						
							|  |  |  |         expect(ngModel.getError('required')).toBe(control.getError('required')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         control.setErrors({required: true}); | 
					
						
							|  |  |  |         expect(ngModel.hasError('required')).toBe(control.hasError('required')); | 
					
						
							|  |  |  |         expect(ngModel.getError('required')).toBe(control.getError('required')); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 14:13:02 -07:00
										 |  |  |       it('should throw when no value accessor with named control', () => { | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |         const namedDir = new NgModel(null !, null !, null !, null !); | 
					
						
							| 
									
										
										
										
											2016-07-13 14:13:02 -07:00
										 |  |  |         namedDir.name = 'one'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(() => namedDir.ngOnChanges({})) | 
					
						
							|  |  |  |             .toThrowError(new RegExp(`No value accessor for form control with name: 'one'`)); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should throw when no value accessor with unnamed control', () => { | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |         const unnamedDir = new NgModel(null !, null !, null !, null !); | 
					
						
							| 
									
										
										
										
											2016-07-13 14:13:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         expect(() => unnamedDir.ngOnChanges({})) | 
					
						
							|  |  |  |             .toThrowError( | 
					
						
							|  |  |  |                 new RegExp(`No value accessor for form control with unspecified name attribute`)); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should set up validator', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |            // this will add the required validator and recalculate the validity
 | 
					
						
							|  |  |  |            ngModel.ngOnChanges({}); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |            expect(ngModel.control.errors).toEqual({'required': true}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 13:35:17 -07:00
										 |  |  |            ngModel.control.setValue('someValue'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |            expect(ngModel.control.errors).toEqual({'async': true}); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should mark as disabled properly', fakeAsync(() => { | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |            ngModel.ngOnChanges({isDisabled: new SimpleChange('', undefined, false)}); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  |            expect(ngModel.control.disabled).toEqual(false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |            ngModel.ngOnChanges({isDisabled: new SimpleChange('', null, false)}); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  |            expect(ngModel.control.disabled).toEqual(false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |            ngModel.ngOnChanges({isDisabled: new SimpleChange('', false, false)}); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  |            expect(ngModel.control.disabled).toEqual(false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |            ngModel.ngOnChanges({isDisabled: new SimpleChange('', 'false', false)}); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  |            expect(ngModel.control.disabled).toEqual(false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |            ngModel.ngOnChanges({isDisabled: new SimpleChange('', 0, false)}); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  |            expect(ngModel.control.disabled).toEqual(false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |            ngModel.ngOnChanges({isDisabled: new SimpleChange(null, '', false)}); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  |            expect(ngModel.control.disabled).toEqual(true); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |            ngModel.ngOnChanges({isDisabled: new SimpleChange(null, 'true', false)}); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  |            expect(ngModel.control.disabled).toEqual(true); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |            ngModel.ngOnChanges({isDisabled: new SimpleChange(null, true, false)}); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  |            expect(ngModel.control.disabled).toEqual(true); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												refactor(compiler): generate less code for bindings to DOM elements
Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```
Performance impact:
- None seen (checked against internal latency lab)
Part of #13651
											
										 
											2016-12-29 15:03:55 -08:00
										 |  |  |            ngModel.ngOnChanges({isDisabled: new SimpleChange(null, 'anything else', false)}); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  |            expect(ngModel.control.disabled).toEqual(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-12 13:17:07 -07:00
										 |  |  |     describe('FormControlName', () => { | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |       let formModel: any /** TODO #9100 */; | 
					
						
							|  |  |  |       let controlNameDir: any /** TODO #9100 */; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |         formModel = new FormControl('name'); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |         const parent = new FormGroupDirective([], []); | 
					
						
							| 
									
										
										
										
											2016-06-10 11:15:59 -07:00
										 |  |  |         parent.form = new FormGroup({'name': formModel}); | 
					
						
							| 
									
										
										
										
											2016-06-12 13:17:07 -07:00
										 |  |  |         controlNameDir = new FormControlName(parent, [], [], [defaultAccessor]); | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         controlNameDir.name = 'name'; | 
					
						
							| 
									
										
										
										
											2016-09-02 15:57:35 -07:00
										 |  |  |         controlNameDir._control = formModel; | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |       it('should reexport control properties', () => { | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(controlNameDir.control).toBe(formModel); | 
					
						
							|  |  |  |         expect(controlNameDir.value).toBe(formModel.value); | 
					
						
							|  |  |  |         expect(controlNameDir.valid).toBe(formModel.valid); | 
					
						
							| 
									
										
										
										
											2016-08-01 18:41:25 -07:00
										 |  |  |         expect(controlNameDir.invalid).toBe(formModel.invalid); | 
					
						
							|  |  |  |         expect(controlNameDir.pending).toBe(formModel.pending); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |         expect(controlNameDir.errors).toBe(formModel.errors); | 
					
						
							|  |  |  |         expect(controlNameDir.pristine).toBe(formModel.pristine); | 
					
						
							|  |  |  |         expect(controlNameDir.dirty).toBe(formModel.dirty); | 
					
						
							|  |  |  |         expect(controlNameDir.touched).toBe(formModel.touched); | 
					
						
							|  |  |  |         expect(controlNameDir.untouched).toBe(formModel.untouched); | 
					
						
							| 
									
										
										
										
											2016-06-24 13:37:42 -07:00
										 |  |  |         expect(controlNameDir.statusChanges).toBe(formModel.statusChanges); | 
					
						
							|  |  |  |         expect(controlNameDir.valueChanges).toBe(formModel.valueChanges); | 
					
						
							| 
									
										
										
										
											2016-08-25 14:56:31 -07:00
										 |  |  |         expect(controlNameDir.disabled).toBe(formModel.disabled); | 
					
						
							|  |  |  |         expect(controlNameDir.enabled).toBe(formModel.enabled); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-10-19 18:49:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should reexport control methods', () => { | 
					
						
							|  |  |  |         expect(controlNameDir.hasError('required')).toBe(formModel.hasError('required')); | 
					
						
							|  |  |  |         expect(controlNameDir.getError('required')).toBe(formModel.getError('required')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         formModel.setErrors({required: true}); | 
					
						
							|  |  |  |         expect(controlNameDir.hasError('required')).toBe(formModel.hasError('required')); | 
					
						
							|  |  |  |         expect(controlNameDir.getError('required')).toBe(formModel.getError('required')); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-06-08 15:36:24 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } |