| 
									
										
										
										
											2016-07-25 15:57:51 -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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-22 19:16:25 -07:00
										 |  |  | import {ɵgetDOM as getDOM} from '@angular/common'; | 
					
						
							| 
									
										
										
										
											2018-02-27 17:06:06 -05:00
										 |  |  | import {Component, Directive, Type, forwardRef} from '@angular/core'; | 
					
						
							| 
									
										
										
										
											2016-12-14 16:34:19 +00:00
										 |  |  | import {ComponentFixture, TestBed, async, fakeAsync, tick} from '@angular/core/testing'; | 
					
						
							| 
									
										
										
										
											2019-10-11 00:55:47 +02:00
										 |  |  | import {AbstractControl, AsyncValidator, COMPOSITION_BUFFER_MODE, FormControl, FormsModule, NG_ASYNC_VALIDATORS, NgForm, NgModel} from '@angular/forms'; | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | import {By} from '@angular/platform-browser/src/dom/debug/by'; | 
					
						
							| 
									
										
										
										
											2019-08-23 12:32:00 -07:00
										 |  |  | import {dispatchEvent, sortedClassList} from '@angular/platform-browser/testing/src/browser_util'; | 
					
						
							| 
									
										
										
										
											2018-02-27 17:06:06 -05:00
										 |  |  | import {merge} from 'rxjs'; | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 11:24:47 -07:00
										 |  |  | import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integration_spec'; | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-16 14:42:55 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  |   describe('template-driven forms integration tests', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |     function initTest<T>(component: Type<T>, ...directives: Type<any>[]): ComponentFixture<T> { | 
					
						
							|  |  |  |       TestBed.configureTestingModule( | 
					
						
							|  |  |  |           {declarations: [component, ...directives], imports: [FormsModule]}); | 
					
						
							|  |  |  |       return TestBed.createComponent(component); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |     describe('basic functionality', () => { | 
					
						
							|  |  |  |       it('should support ngModel for standalone fields', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(StandaloneNgModel); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.name = 'oldValue'; | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            // model -> view
 | 
					
						
							|  |  |  |            const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |            expect(input.value).toEqual('oldValue'); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            input.value = 'updatedValue'; | 
					
						
							|  |  |  |            dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            // view -> model
 | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            expect(fixture.componentInstance.name).toEqual('updatedValue'); | 
					
						
							| 
									
										
										
										
											2017-01-12 20:02:45 +08:00
										 |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should support ngModel registration with a parent form', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.name = 'Nancy'; | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            expect(form.value).toEqual({name: 'Nancy'}); | 
					
						
							|  |  |  |            expect(form.valid).toBe(false); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-12 17:12:36 -08:00
										 |  |  |       it('should report properties which are written outside of template bindings', async() => { | 
					
						
							|  |  |  |         // For example ngModel writes to `checked` property programmatically
 | 
					
						
							|  |  |  |         // (template does not contain binding to `checked` explicitly)
 | 
					
						
							|  |  |  |         // https://github.com/angular/angular/issues/33695
 | 
					
						
							|  |  |  |         @Component({ | 
					
						
							|  |  |  |           selector: 'app-root', | 
					
						
							|  |  |  |           template: `<input type="radio" value="one" [(ngModel)]="active"/>` | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         class AppComponent { | 
					
						
							|  |  |  |           active = 'one'; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         TestBed.configureTestingModule({imports: [FormsModule], declarations: [AppComponent]}); | 
					
						
							|  |  |  |         const fixture = TestBed.createComponent(AppComponent); | 
					
						
							|  |  |  |         // We need the Await as `ngModel` writes data asynchronously into the DOM
 | 
					
						
							|  |  |  |         await fixture.detectChanges(); | 
					
						
							|  |  |  |         const input = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  |         expect(input.properties.checked).toBe(true); | 
					
						
							|  |  |  |         expect(input.nativeElement.checked).toBe(true); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-12 22:17:42 +03:00
										 |  |  |       it('should add novalidate by default to form element', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2016-12-12 22:17:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.query(By.css('form')); | 
					
						
							|  |  |  |            expect(form.nativeElement.getAttribute('novalidate')).toEqual(''); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-21 03:36:48 +03:00
										 |  |  |       it('should be possible to use native validation and angular forms', fakeAsync(() => { | 
					
						
							|  |  |  |            const fixture = initTest(NgModelNativeValidateForm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.query(By.css('form')); | 
					
						
							|  |  |  |            expect(form.nativeElement.hasAttribute('novalidate')).toEqual(false); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should support ngModelGroup', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelGroupForm); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.first = 'Nancy'; | 
					
						
							|  |  |  |            fixture.componentInstance.last = 'Drew'; | 
					
						
							|  |  |  |            fixture.componentInstance.email = 'some email'; | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            // model -> view
 | 
					
						
							|  |  |  |            const inputs = fixture.debugElement.queryAll(By.css('input')); | 
					
						
							|  |  |  |            expect(inputs[0].nativeElement.value).toEqual('Nancy'); | 
					
						
							|  |  |  |            expect(inputs[1].nativeElement.value).toEqual('Drew'); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            inputs[0].nativeElement.value = 'Carson'; | 
					
						
							|  |  |  |            dispatchEvent(inputs[0].nativeElement, 'input'); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            // view -> model
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            expect(form.value).toEqual({name: {first: 'Carson', last: 'Drew'}, email: 'some email'}); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should add controls and control groups to form control model', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelGroupForm); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.first = 'Nancy'; | 
					
						
							|  |  |  |            fixture.componentInstance.last = 'Drew'; | 
					
						
							|  |  |  |            fixture.componentInstance.email = 'some email'; | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            expect(form.control.get('name') !.value).toEqual({first: 'Nancy', last: 'Drew'}); | 
					
						
							|  |  |  |            expect(form.control.get('name.first') !.value).toEqual('Nancy'); | 
					
						
							|  |  |  |            expect(form.control.get('email') !.value).toEqual('some email'); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should remove controls and control groups from form control model', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelNgIfForm); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.emailShowing = true; | 
					
						
							|  |  |  |            fixture.componentInstance.first = 'Nancy'; | 
					
						
							|  |  |  |            fixture.componentInstance.email = 'some email'; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            expect(form.control.get('email') !.value).toEqual('some email'); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            expect(form.value).toEqual({name: {first: 'Nancy'}, email: 'some email'}); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            // should remove individual control successfully
 | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.emailShowing = false; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            expect(form.control.get('email')).toBe(null); | 
					
						
							|  |  |  |            expect(form.value).toEqual({name: {first: 'Nancy'}}); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            expect(form.control.get('name') !.value).toEqual({first: 'Nancy'}); | 
					
						
							|  |  |  |            expect(form.control.get('name.first') !.value).toEqual('Nancy'); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            // should remove form group successfully
 | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.groupShowing = false; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            expect(form.control.get('name')).toBe(null); | 
					
						
							|  |  |  |            expect(form.control.get('name.first')).toBe(null); | 
					
						
							|  |  |  |            expect(form.value).toEqual({}); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-19 14:55:57 -08:00
										 |  |  |       it('should set status classes with ngModel', async(() => { | 
					
						
							|  |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |            fixture.componentInstance.name = 'aa'; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            fixture.whenStable().then(() => { | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              expect(sortedClassList(input)).toEqual(['ng-invalid', 'ng-pristine', 'ng-untouched']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(sortedClassList(input)).toEqual(['ng-invalid', 'ng-pristine', 'ng-touched']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              input.value = 'updatedValue'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              expect(sortedClassList(input)).toEqual(['ng-dirty', 'ng-touched', 'ng-valid']); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should set status classes with ngModel and async validators', fakeAsync(() => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const fixture = initTest(NgModelAsyncValidation, NgAsyncValidator); | 
					
						
							|  |  |  |            fixture.whenStable().then(() => { | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              expect(sortedClassList(input)).toEqual(['ng-pending', 'ng-pristine', 'ng-untouched']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(sortedClassList(input)).toEqual(['ng-pending', 'ng-pristine', 'ng-touched']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              input.value = 'updatedValue'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(sortedClassList(input)).toEqual(['ng-dirty', 'ng-touched', 'ng-valid']); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should set status classes with ngModelGroup and ngForm', async(() => { | 
					
						
							|  |  |  |            const fixture = initTest(NgModelGroupForm); | 
					
						
							|  |  |  |            fixture.componentInstance.first = ''; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							|  |  |  |            const modelGroup = fixture.debugElement.query(By.css('[ngModelGroup]')).nativeElement; | 
					
						
							|  |  |  |            const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // ngModelGroup creates its control asynchronously
 | 
					
						
							|  |  |  |            fixture.whenStable().then(() => { | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              expect(sortedClassList(modelGroup)).toEqual([ | 
					
						
							|  |  |  |                'ng-invalid', 'ng-pristine', 'ng-untouched' | 
					
						
							|  |  |  |              ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(sortedClassList(form)).toEqual(['ng-invalid', 'ng-pristine', 'ng-untouched']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(sortedClassList(modelGroup)).toEqual([ | 
					
						
							|  |  |  |                'ng-invalid', 'ng-pristine', 'ng-touched' | 
					
						
							|  |  |  |              ]); | 
					
						
							|  |  |  |              expect(sortedClassList(form)).toEqual(['ng-invalid', 'ng-pristine', 'ng-touched']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              input.value = 'updatedValue'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(sortedClassList(modelGroup)).toEqual(['ng-dirty', 'ng-touched', 'ng-valid']); | 
					
						
							|  |  |  |              expect(sortedClassList(form)).toEqual(['ng-dirty', 'ng-touched', 'ng-valid']); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should not create a template-driven form when ngNoForm is used', () => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |         const fixture = initTest(NgNoFormComp); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |         fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |         expect(fixture.debugElement.children[0].providerTokens !.length).toEqual(0); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-12-12 22:17:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should not add novalidate when ngNoForm is used', () => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |         const fixture = initTest(NgNoFormComp); | 
					
						
							| 
									
										
										
										
											2016-12-12 22:17:42 +03:00
										 |  |  |         fixture.detectChanges(); | 
					
						
							|  |  |  |         const form = fixture.debugElement.query(By.css('form')); | 
					
						
							| 
									
										
										
										
											2017-02-21 03:36:48 +03:00
										 |  |  |         expect(form.nativeElement.hasAttribute('novalidate')).toEqual(false); | 
					
						
							| 
									
										
										
										
											2016-12-12 22:17:42 +03:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |     describe('name and ngModelOptions', () => { | 
					
						
							|  |  |  |       it('should throw if ngModel has a parent form but no name attr or standalone label', () => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |         const fixture = initTest(InvalidNgModelNoName); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |         expect(() => fixture.detectChanges()) | 
					
						
							|  |  |  |             .toThrowError(new RegExp(`name attribute must be set`)); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not throw if ngModel has a parent form, no name attr, and a standalone label', | 
					
						
							|  |  |  |          () => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelOptionsStandalone); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            expect(() => fixture.detectChanges()).not.toThrow(); | 
					
						
							|  |  |  |          }); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should not register standalone ngModels with parent form', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelOptionsStandalone); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.one = 'some data'; | 
					
						
							|  |  |  |            fixture.componentInstance.two = 'should not show'; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            const inputs = fixture.debugElement.queryAll(By.css('input')); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            expect(form.value).toEqual({one: 'some data'}); | 
					
						
							|  |  |  |            expect(inputs[1].nativeElement.value).toEqual('should not show'); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should override name attribute with ngModelOptions name if provided', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.options = {name: 'override'}; | 
					
						
							|  |  |  |            fixture.componentInstance.name = 'some data'; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            expect(form.value).toEqual({override: 'some data'}); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |     describe('updateOn', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe('blur', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should default updateOn to change', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              const name = form.control.get('name') as FormControl; | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |              expect((name as any)._updateOn).toBeUndefined(); | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |              expect(name.updateOn).toEqual('change'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should set control updateOn to blur properly', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              const name = form.control.get('name') as FormControl; | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |              expect((name as any)._updateOn).toEqual('blur'); | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |              expect(name.updateOn).toEqual('blur'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should always set value and validity on init', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Nancy Drew'; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(input.value).toEqual('Nancy Drew', 'Expected initial view value to be set.'); | 
					
						
							|  |  |  |              expect(form.value) | 
					
						
							|  |  |  |                  .toEqual({name: 'Nancy Drew'}, 'Expected initial control value be set.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(true, 'Expected validation to run on initial value.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should always set value programmatically right away', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Nancy Drew'; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Carson'; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(input.value) | 
					
						
							|  |  |  |                  .toEqual('Carson', 'Expected view value to update on programmatic change.'); | 
					
						
							|  |  |  |              expect(form.value) | 
					
						
							|  |  |  |                  .toEqual( | 
					
						
							|  |  |  |                      {name: 'Carson'}, 'Expected form value to update on programmatic change.'); | 
					
						
							|  |  |  |              expect(form.valid) | 
					
						
							|  |  |  |                  .toBe(false, 'Expected validation to run immediately on programmatic change.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should update value/validity on blur', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Carson'; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual('Carson', 'Expected value not to update on input.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(false, 'Expected validation not to run on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual('Nancy Drew', 'Expected value to update on blur.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(true, 'Expected validation to run on blur.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should wait for second blur to update value/validity again', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Carson'; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              input.value = 'Carson'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual('Nancy Drew', 'Expected value not to update until another blur.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(true, 'Expected validation not to run until another blur.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual('Carson', 'Expected value to update on second blur.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(false, 'Expected validation to run on second blur.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should not update dirtiness until blur', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(form.dirty).toBe(false, 'Expected dirtiness not to update on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(form.dirty).toBe(true, 'Expected dirtiness to update on blur.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should not update touched until blur', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(form.touched).toBe(false, 'Expected touched not to update on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(form.touched).toBe(true, 'Expected touched to update on blur.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should not emit valueChanges or statusChanges until blur', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |              const values: any[] = []; | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const sub = merge(form.valueChanges !, form.statusChanges !) | 
					
						
							|  |  |  |                              .subscribe(val => values.push(val)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(values).toEqual([], 'Expected no valueChanges or statusChanges on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(values).toEqual( | 
					
						
							|  |  |  |                  [{name: 'Nancy Drew'}, 'VALID'], | 
					
						
							|  |  |  |                  'Expected valueChanges and statusChanges on blur.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              sub.unsubscribe(); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 02:54:36 -08:00
										 |  |  |         it('should not fire ngModelChange event on blur unless value has changed', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelChangesForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Carson'; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual([], 'Expected ngModelChanges not to fire.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual([], 'Expected ngModelChanges not to fire if value unchanged.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              input.value = 'Carson'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual([], 'Expected ngModelChanges not to fire on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual( | 
					
						
							|  |  |  |                      ['fired'], 'Expected ngModelChanges to fire once blurred if value changed.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual( | 
					
						
							|  |  |  |                      ['fired'], | 
					
						
							|  |  |  |                      'Expected ngModelChanges not to fire again on blur unless value changed.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              input.value = 'Bess'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual(['fired'], 'Expected ngModelChanges not to fire on input after blur.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual( | 
					
						
							|  |  |  |                      ['fired', 'fired'], | 
					
						
							|  |  |  |                      'Expected ngModelChanges to fire again on blur if value changed.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe('submit', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should set control updateOn to submit properly', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              const name = form.control.get('name') as FormControl; | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |              expect((name as any)._updateOn).toEqual('submit'); | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |              expect(name.updateOn).toEqual('submit'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should always set value and validity on init', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Nancy Drew'; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(input.value).toEqual('Nancy Drew', 'Expected initial view value to be set.'); | 
					
						
							|  |  |  |              expect(form.value) | 
					
						
							|  |  |  |                  .toEqual({name: 'Nancy Drew'}, 'Expected initial control value be set.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(true, 'Expected validation to run on initial value.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should always set value programmatically right away', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Nancy Drew'; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Carson'; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(input.value) | 
					
						
							|  |  |  |                  .toEqual('Carson', 'Expected view value to update on programmatic change.'); | 
					
						
							|  |  |  |              expect(form.value) | 
					
						
							|  |  |  |                  .toEqual( | 
					
						
							|  |  |  |                      {name: 'Carson'}, 'Expected form value to update on programmatic change.'); | 
					
						
							|  |  |  |              expect(form.valid) | 
					
						
							|  |  |  |                  .toBe(false, 'Expected validation to run immediately on programmatic change.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should update on submit', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Carson'; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual('Carson', 'Expected value not to update on input.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(false, 'Expected validation not to run on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual('Carson', 'Expected value not to update on blur.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(false, 'Expected validation not to run on blur.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const formEl = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual('Nancy Drew', 'Expected value to update on submit.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(true, 'Expected validation to run on submit.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should wait until second submit to update again', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Carson'; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const formEl = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              input.value = 'Carson'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual('Nancy Drew', 'Expected value not to update until second submit.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(true, 'Expected validation not to run until second submit.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual('Carson', 'Expected value to update on second submit.'); | 
					
						
							|  |  |  |              expect(form.valid).toBe(false, 'Expected validation to run on second submit.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should not run validation for onChange controls on submit', fakeAsync(() => { | 
					
						
							|  |  |  |              const validatorSpy = jasmine.createSpy('validator'); | 
					
						
							|  |  |  |              const groupValidatorSpy = jasmine.createSpy('groupValidatorSpy'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const fixture = initTest(NgModelGroupForm); | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              form.control.get('name') !.setValidators(groupValidatorSpy); | 
					
						
							|  |  |  |              form.control.get('name.last') !.setValidators(validatorSpy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const formEl = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(validatorSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(groupValidatorSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should not update dirtiness until submit', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(form.dirty).toBe(false, 'Expected dirtiness not to update on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(form.dirty).toBe(false, 'Expected dirtiness not to update on blur.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const formEl = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(form.dirty).toBe(true, 'Expected dirtiness to update on submit.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should not update touched until submit', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(form.touched).toBe(false, 'Expected touched not to update on blur.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const formEl = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(form.touched).toBe(true, 'Expected touched to update on submit.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should reset properly', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |              fixture.componentInstance.name = 'Nancy' as string | null; | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              form.resetForm(); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(input.value).toEqual('', 'Expected view value to reset.'); | 
					
						
							|  |  |  |              expect(form.value).toEqual({name: null}, 'Expected form value to reset.'); | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual(null, 'Expected ngModel value to reset.'); | 
					
						
							|  |  |  |              expect(form.dirty).toBe(false, 'Expected dirty to stay false on reset.'); | 
					
						
							|  |  |  |              expect(form.touched).toBe(false, 'Expected touched to stay false on reset.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const formEl = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(form.value) | 
					
						
							|  |  |  |                  .toEqual({name: null}, 'Expected form value to stay empty on submit'); | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name) | 
					
						
							|  |  |  |                  .toEqual(null, 'Expected ngModel value to stay empty on submit.'); | 
					
						
							|  |  |  |              expect(form.dirty).toBe(false, 'Expected dirty to stay false on submit.'); | 
					
						
							|  |  |  |              expect(form.touched).toBe(false, 'Expected touched to stay false on submit.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should not emit valueChanges or statusChanges until submit', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |              const values: any[] = []; | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const sub = merge(form.valueChanges !, form.statusChanges !) | 
					
						
							|  |  |  |                              .subscribe(val => values.push(val)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(values).toEqual([], 'Expected no valueChanges or statusChanges on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(values).toEqual([], 'Expected no valueChanges or statusChanges on blur.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const formEl = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(values).toEqual( | 
					
						
							|  |  |  |                  [{name: 'Nancy Drew'}, 'VALID'], | 
					
						
							|  |  |  |                  'Expected valueChanges and statusChanges on submit.'); | 
					
						
							|  |  |  |              sub.unsubscribe(); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 02:54:36 -08:00
										 |  |  |         it('should not fire ngModelChange event on submit unless value has changed', | 
					
						
							|  |  |  |            fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelChangesForm); | 
					
						
							|  |  |  |              fixture.componentInstance.name = 'Carson'; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'submit'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const formEl = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual([], 'Expected ngModelChanges not to fire if value unchanged.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Carson'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual([], 'Expected ngModelChanges not to fire on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual( | 
					
						
							|  |  |  |                      ['fired'], 'Expected ngModelChanges to fire once submitted if value changed.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual( | 
					
						
							|  |  |  |                      ['fired'], | 
					
						
							|  |  |  |                      'Expected ngModelChanges not to fire again on submit unless value changed.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              input.value = 'Bess'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual(['fired'], 'Expected ngModelChanges not to fire on input after submit.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.events) | 
					
						
							|  |  |  |                  .toEqual( | 
					
						
							|  |  |  |                      ['fired', 'fired'], | 
					
						
							|  |  |  |                      'Expected ngModelChanges to fire again on submit if value changed.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-08 14:37:29 -07:00
										 |  |  |       describe('ngFormOptions', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should use ngFormOptions value when ngModelOptions are not set', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelOptionsStandalone); | 
					
						
							|  |  |  |              fixture.componentInstance.options = {name: 'two'}; | 
					
						
							|  |  |  |              fixture.componentInstance.formOptions = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              const controlOne = form.control.get('one') !as FormControl; | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |              expect((controlOne as any)._updateOn).toBeUndefined(); | 
					
						
							| 
									
										
										
										
											2017-08-08 14:37:29 -07:00
										 |  |  |              expect(controlOne.updateOn) | 
					
						
							|  |  |  |                  .toEqual('blur', 'Expected first control to inherit updateOn from parent form.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const controlTwo = form.control.get('two') !as FormControl; | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |              expect((controlTwo as any)._updateOn).toBeUndefined(); | 
					
						
							| 
									
										
										
										
											2017-08-08 14:37:29 -07:00
										 |  |  |              expect(controlTwo.updateOn) | 
					
						
							|  |  |  |                  .toEqual('blur', 'Expected last control to inherit updateOn from parent form.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should actually update using ngFormOptions value', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelOptionsStandalone); | 
					
						
							|  |  |  |              fixture.componentInstance.one = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.formOptions = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |              input.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(input, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(form.value).toEqual({one: ''}, 'Expected value not to update on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(input, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(form.value).toEqual({one: 'Nancy Drew'}, 'Expected value to update on blur.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should allow ngModelOptions updateOn to override ngFormOptions', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelOptionsStandalone); | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur', name: 'two'}; | 
					
						
							|  |  |  |              fixture.componentInstance.formOptions = {updateOn: 'change'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              const controlOne = form.control.get('one') !as FormControl; | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |              expect((controlOne as any)._updateOn).toBeUndefined(); | 
					
						
							| 
									
										
										
										
											2017-08-08 14:37:29 -07:00
										 |  |  |              expect(controlOne.updateOn) | 
					
						
							|  |  |  |                  .toEqual('change', 'Expected control updateOn to inherit form updateOn.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const controlTwo = form.control.get('two') !as FormControl; | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |              expect((controlTwo as any)._updateOn) | 
					
						
							|  |  |  |                  .toEqual('blur', 'Expected control to set blur override.'); | 
					
						
							| 
									
										
										
										
											2017-08-08 14:37:29 -07:00
										 |  |  |              expect(controlTwo.updateOn) | 
					
						
							|  |  |  |                  .toEqual('blur', 'Expected control updateOn to override form updateOn.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should update using ngModelOptions override', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelOptionsStandalone); | 
					
						
							|  |  |  |              fixture.componentInstance.one = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.two = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {updateOn: 'blur', name: 'two'}; | 
					
						
							|  |  |  |              fixture.componentInstance.formOptions = {updateOn: 'change'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const [inputOne, inputTwo] = fixture.debugElement.queryAll(By.css('input')); | 
					
						
							|  |  |  |              inputOne.nativeElement.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(inputOne.nativeElement, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |              expect(form.value) | 
					
						
							|  |  |  |                  .toEqual({one: 'Nancy Drew', two: ''}, 'Expected first value to update on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              inputTwo.nativeElement.value = 'Carson Drew'; | 
					
						
							|  |  |  |              dispatchEvent(inputTwo.nativeElement, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(form.value) | 
					
						
							|  |  |  |                  .toEqual( | 
					
						
							|  |  |  |                      {one: 'Nancy Drew', two: ''}, 'Expected second value not to update on input.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              dispatchEvent(inputTwo.nativeElement, 'blur'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(form.value) | 
					
						
							|  |  |  |                  .toEqual( | 
					
						
							|  |  |  |                      {one: 'Nancy Drew', two: 'Carson Drew'}, | 
					
						
							|  |  |  |                      'Expected second value to update on blur.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should not use ngFormOptions for standalone ngModels', fakeAsync(() => { | 
					
						
							|  |  |  |              const fixture = initTest(NgModelOptionsStandalone); | 
					
						
							|  |  |  |              fixture.componentInstance.two = ''; | 
					
						
							|  |  |  |              fixture.componentInstance.options = {standalone: true}; | 
					
						
							|  |  |  |              fixture.componentInstance.formOptions = {updateOn: 'blur'}; | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const inputTwo = fixture.debugElement.queryAll(By.css('input'))[1].nativeElement; | 
					
						
							|  |  |  |              inputTwo.value = 'Nancy Drew'; | 
					
						
							|  |  |  |              dispatchEvent(inputTwo, 'input'); | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.two) | 
					
						
							|  |  |  |                  .toEqual('Nancy Drew', 'Expected standalone ngModel not to inherit blur update.'); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |     describe('submit and reset events', () => { | 
					
						
							| 
									
										
										
										
											2016-10-11 23:49:36 +01:00
										 |  |  |       it('should emit ngSubmit event with the original submit event on submit', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            fixture.componentInstance.event = null !; | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const form = fixture.debugElement.query(By.css('form')); | 
					
						
							|  |  |  |            dispatchEvent(form.nativeElement, 'submit'); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-11 23:49:36 +01:00
										 |  |  |            expect(fixture.componentInstance.event.type).toEqual('submit'); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should mark NgForm as submitted on submit event', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            tick(); | 
					
						
							|  |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            expect(form.submitted).toBe(false); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const formEl = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							|  |  |  |            dispatchEvent(formEl, 'submit'); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            expect(form.submitted).toBe(true); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-08-11 23:27:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should reset the form to empty when reset event is fired', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |            fixture.componentInstance.name = 'should be cleared' as string | null; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-08-11 23:27:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            const formEl = fixture.debugElement.query(By.css('form')); | 
					
						
							|  |  |  |            const input = fixture.debugElement.query(By.css('input')); | 
					
						
							| 
									
										
										
										
											2016-08-11 23:27:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            expect(input.nativeElement.value).toBe('should be cleared');       // view value
 | 
					
						
							|  |  |  |            expect(fixture.componentInstance.name).toBe('should be cleared');  // ngModel value
 | 
					
						
							|  |  |  |            expect(form.value.name).toEqual('should be cleared');              // control value
 | 
					
						
							| 
									
										
										
										
											2016-08-11 23:27:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            dispatchEvent(formEl.nativeElement, 'reset'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-08-11 23:27:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            expect(input.nativeElement.value).toBe('');         // view value
 | 
					
						
							|  |  |  |            expect(fixture.componentInstance.name).toBe(null);  // ngModel value
 | 
					
						
							|  |  |  |            expect(form.value.name).toEqual(null);              // control value
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should reset the form submit state when reset button is clicked', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            const formEl = fixture.debugElement.query(By.css('form')); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            dispatchEvent(formEl.nativeElement, 'submit'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  |            expect(form.submitted).toBe(true); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            dispatchEvent(formEl.nativeElement, 'reset'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  |            expect(form.submitted).toBe(false); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |     describe('valueChange and statusChange events', () => { | 
					
						
							|  |  |  |       it('should emit valueChanges and statusChanges on init', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.name = 'aa'; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            expect(form.valid).toEqual(true); | 
					
						
							|  |  |  |            expect(form.value).toEqual({}); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            let formValidity: string = undefined !; | 
					
						
							|  |  |  |            let formValue: Object = undefined !; | 
					
						
							| 
									
										
										
										
											2016-08-02 15:53:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            form.statusChanges !.subscribe((status: string) => formValidity = status); | 
					
						
							|  |  |  |            form.valueChanges !.subscribe((value: string) => formValue = value); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            expect(formValidity).toEqual('INVALID'); | 
					
						
							|  |  |  |            expect(formValue).toEqual({name: 'aa'}); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should mark controls dirty before emitting the value change event', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm).form; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            form.get('name') !.valueChanges.subscribe( | 
					
						
							|  |  |  |                () => { expect(form.get('name') !.dirty).toBe(true); }); | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const inputEl = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							|  |  |  |            inputEl.value = 'newValue'; | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            dispatchEvent(inputEl, 'input'); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should mark controls pristine before emitting the value change event when resetting ', | 
					
						
							|  |  |  |          fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm).form; | 
					
						
							|  |  |  |            const formEl = fixture.debugElement.query(By.css('form')).nativeElement; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const inputEl = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            inputEl.value = 'newValue'; | 
					
						
							|  |  |  |            dispatchEvent(inputEl, 'input'); | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            expect(form.get('name') !.pristine).toBe(false); | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            form.get('name') !.valueChanges.subscribe( | 
					
						
							|  |  |  |                () => { expect(form.get('name') !.pristine).toBe(true); }); | 
					
						
							| 
									
										
										
										
											2016-07-28 14:25:33 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |            dispatchEvent(formEl, 'reset'); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |          })); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  |     describe('disabled controls', () => { | 
					
						
							|  |  |  |       it('should not consider disabled controls in value or validation', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelGroupForm); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.isDisabled = false; | 
					
						
							|  |  |  |            fixture.componentInstance.first = ''; | 
					
						
							|  |  |  |            fixture.componentInstance.last = 'Drew'; | 
					
						
							|  |  |  |            fixture.componentInstance.email = 'some email'; | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            expect(form.value).toEqual({name: {first: '', last: 'Drew'}, email: 'some email'}); | 
					
						
							|  |  |  |            expect(form.valid).toBe(false); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            expect(form.control.get('name.first') !.disabled).toBe(false); | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |            fixture.componentInstance.isDisabled = true; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(form.value).toEqual({name: {last: 'Drew'}, email: 'some email'}); | 
					
						
							|  |  |  |            expect(form.valid).toBe(true); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            expect(form.control.get('name.first') !.disabled).toBe(true); | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should add disabled attribute in the UI if disable() is called programmatically', | 
					
						
							|  |  |  |          fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelGroupForm); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.isDisabled = false; | 
					
						
							|  |  |  |            fixture.componentInstance.first = 'Nancy'; | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            form.control.get('name.first') !.disable(); | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const input = fixture.debugElement.query(By.css(`[name="first"]`)); | 
					
						
							|  |  |  |            expect(input.nativeElement.disabled).toBe(true); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 15:57:17 -08:00
										 |  |  |       it('should disable a custom control if disabled attr is added', async(() => { | 
					
						
							|  |  |  |            const fixture = initTest(NgModelCustomWrapper, NgModelCustomComp); | 
					
						
							|  |  |  |            fixture.componentInstance.name = 'Nancy'; | 
					
						
							|  |  |  |            fixture.componentInstance.isDisabled = true; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            fixture.whenStable().then(() => { | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              fixture.whenStable().then(() => { | 
					
						
							|  |  |  |                const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |                expect(form.control.get('name') !.disabled).toBe(true); | 
					
						
							| 
									
										
										
										
											2018-11-06 14:02:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 15:57:17 -08:00
										 |  |  |                const customInput = fixture.debugElement.query(By.css('[name="custom"]')); | 
					
						
							|  |  |  |                expect(customInput.nativeElement.disabled).toEqual(true); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |       it('should disable a control with unbound disabled attr', fakeAsync(() => { | 
					
						
							|  |  |  |            TestBed.overrideComponent(NgModelForm, { | 
					
						
							|  |  |  |              set: { | 
					
						
							|  |  |  |                template: `
 | 
					
						
							|  |  |  |             <form> | 
					
						
							|  |  |  |              <input name="name" [(ngModel)]="name" disabled> | 
					
						
							|  |  |  |             </form> | 
					
						
							|  |  |  |           `,
 | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelForm); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |            expect(form.control.get('name') !.disabled).toBe(true); | 
					
						
							| 
									
										
										
										
											2016-09-20 14:55:47 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |            const input = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  |            expect(input.nativeElement.disabled).toEqual(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            form.control.enable(); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  |            expect(input.nativeElement.disabled).toEqual(false); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-29 11:33:49 -07:00
										 |  |  |     describe('validation directives', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 11:46:33 -08:00
										 |  |  |       it('required validator should validate checkbox', fakeAsync(() => { | 
					
						
							|  |  |  |            const fixture = initTest(NgModelCheckboxRequiredValidator); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 11:46:33 -08:00
										 |  |  |            const control = | 
					
						
							|  |  |  |                fixture.debugElement.children[0].injector.get(NgForm).control.get('checkbox') !; | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 11:46:33 -08:00
										 |  |  |            const input = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  |            expect(input.nativeElement.checked).toBe(false); | 
					
						
							|  |  |  |            expect(control.hasError('required')).toBe(false); | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 11:46:33 -08:00
										 |  |  |            fixture.componentInstance.required = true; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 11:46:33 -08:00
										 |  |  |            expect(input.nativeElement.checked).toBe(false); | 
					
						
							|  |  |  |            expect(control.hasError('required')).toBe(true); | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 11:46:33 -08:00
										 |  |  |            input.nativeElement.checked = true; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'change'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 11:46:33 -08:00
										 |  |  |            expect(input.nativeElement.checked).toBe(true); | 
					
						
							|  |  |  |            expect(control.hasError('required')).toBe(false); | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 11:46:33 -08:00
										 |  |  |            input.nativeElement.checked = false; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'change'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 11:46:33 -08:00
										 |  |  |            expect(input.nativeElement.checked).toBe(false); | 
					
						
							|  |  |  |            expect(control.hasError('required')).toBe(true); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-29 20:07:02 +03:00
										 |  |  |       it('should validate email', fakeAsync(() => { | 
					
						
							|  |  |  |            const fixture = initTest(NgModelEmailValidator); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const control = | 
					
						
							| 
									
										
										
										
											2017-04-17 11:13:30 -07:00
										 |  |  |                fixture.debugElement.children[0].injector.get(NgForm).control.get('email') !; | 
					
						
							| 
									
										
										
										
											2016-12-29 20:07:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |            const input = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  |            expect(control.hasError('email')).toBe(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            fixture.componentInstance.validatorEnabled = true; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(input.nativeElement.value).toEqual(''); | 
					
						
							| 
									
										
										
										
											2017-12-07 17:24:49 +11:00
										 |  |  |            expect(control.hasError('email')).toBe(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            input.nativeElement.value = '@'; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'input'); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(input.nativeElement.value).toEqual('@'); | 
					
						
							| 
									
										
										
										
											2016-12-29 20:07:02 +03:00
										 |  |  |            expect(control.hasError('email')).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            input.nativeElement.value = 'test@gmail.com'; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'input'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(input.nativeElement.value).toEqual('test@gmail.com'); | 
					
						
							|  |  |  |            expect(control.hasError('email')).toBe(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            input.nativeElement.value = 'text'; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'input'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(input.nativeElement.value).toEqual('text'); | 
					
						
							|  |  |  |            expect(control.hasError('email')).toBe(true); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-29 11:33:49 -07:00
										 |  |  |       it('should support dir validators using bindings', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelValidationBindings); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.required = true; | 
					
						
							|  |  |  |            fixture.componentInstance.minLen = 3; | 
					
						
							|  |  |  |            fixture.componentInstance.maxLen = 3; | 
					
						
							|  |  |  |            fixture.componentInstance.pattern = '.{3,}'; | 
					
						
							| 
									
										
										
										
											2016-08-29 11:33:49 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const required = fixture.debugElement.query(By.css('[name=required]')); | 
					
						
							|  |  |  |            const minLength = fixture.debugElement.query(By.css('[name=minlength]')); | 
					
						
							|  |  |  |            const maxLength = fixture.debugElement.query(By.css('[name=maxlength]')); | 
					
						
							|  |  |  |            const pattern = fixture.debugElement.query(By.css('[name=pattern]')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            required.nativeElement.value = ''; | 
					
						
							|  |  |  |            minLength.nativeElement.value = '1'; | 
					
						
							|  |  |  |            maxLength.nativeElement.value = '1234'; | 
					
						
							|  |  |  |            pattern.nativeElement.value = '12'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            dispatchEvent(required.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(minLength.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(maxLength.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(pattern.nativeElement, 'input'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            expect(form.control.hasError('required', ['required'])).toEqual(true); | 
					
						
							|  |  |  |            expect(form.control.hasError('minlength', ['minlength'])).toEqual(true); | 
					
						
							|  |  |  |            expect(form.control.hasError('maxlength', ['maxlength'])).toEqual(true); | 
					
						
							|  |  |  |            expect(form.control.hasError('pattern', ['pattern'])).toEqual(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            required.nativeElement.value = '1'; | 
					
						
							|  |  |  |            minLength.nativeElement.value = '123'; | 
					
						
							|  |  |  |            maxLength.nativeElement.value = '123'; | 
					
						
							|  |  |  |            pattern.nativeElement.value = '123'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            dispatchEvent(required.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(minLength.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(maxLength.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(pattern.nativeElement, 'input'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(form.valid).toEqual(true); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 05:48:34 +03:00
										 |  |  |       it('should support optional fields with string pattern validator', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelMultipleValidators); | 
					
						
							| 
									
										
										
										
											2016-10-10 18:17:45 +02:00
										 |  |  |            fixture.componentInstance.required = false; | 
					
						
							|  |  |  |            fixture.componentInstance.pattern = '[a-z]+'; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            const input = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            input.nativeElement.value = ''; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'input'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            expect(form.valid).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            input.nativeElement.value = '1'; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'input'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            expect(form.valid).toBeFalsy(); | 
					
						
							|  |  |  |            expect(form.control.hasError('pattern', ['tovalidate'])).toBeTruthy(); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 05:48:34 +03:00
										 |  |  |       it('should support optional fields with RegExp pattern validator', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelMultipleValidators); | 
					
						
							| 
									
										
										
										
											2016-11-16 05:48:34 +03:00
										 |  |  |            fixture.componentInstance.required = false; | 
					
						
							|  |  |  |            fixture.componentInstance.pattern = /^[a-z]+$/; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            const input = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            input.nativeElement.value = ''; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'input'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            expect(form.valid).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            input.nativeElement.value = '1'; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'input'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            expect(form.valid).toBeFalsy(); | 
					
						
							|  |  |  |            expect(form.control.hasError('pattern', ['tovalidate'])).toBeTruthy(); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-10 18:17:45 +02:00
										 |  |  |       it('should support optional fields with minlength validator', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelMultipleValidators); | 
					
						
							| 
									
										
										
										
											2016-10-10 18:17:45 +02:00
										 |  |  |            fixture.componentInstance.required = false; | 
					
						
							|  |  |  |            fixture.componentInstance.minLen = 2; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            const input = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            input.nativeElement.value = ''; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'input'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            expect(form.valid).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            input.nativeElement.value = '1'; | 
					
						
							|  |  |  |            dispatchEvent(input.nativeElement, 'input'); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            expect(form.valid).toBeFalsy(); | 
					
						
							|  |  |  |            expect(form.control.hasError('minlength', ['tovalidate'])).toBeTruthy(); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 19:05:06 -08:00
										 |  |  |       it('changes on bound properties should change the validation state of the form', | 
					
						
							|  |  |  |          fakeAsync(() => { | 
					
						
							|  |  |  |            const fixture = initTest(NgModelValidationBindings); | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-08-29 11:33:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 19:05:06 -08:00
										 |  |  |            const required = fixture.debugElement.query(By.css('[name=required]')); | 
					
						
							|  |  |  |            const minLength = fixture.debugElement.query(By.css('[name=minlength]')); | 
					
						
							|  |  |  |            const maxLength = fixture.debugElement.query(By.css('[name=maxlength]')); | 
					
						
							|  |  |  |            const pattern = fixture.debugElement.query(By.css('[name=pattern]')); | 
					
						
							| 
									
										
										
										
											2016-08-29 11:33:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 19:05:06 -08:00
										 |  |  |            required.nativeElement.value = ''; | 
					
						
							|  |  |  |            minLength.nativeElement.value = '1'; | 
					
						
							|  |  |  |            maxLength.nativeElement.value = '1234'; | 
					
						
							|  |  |  |            pattern.nativeElement.value = '12'; | 
					
						
							| 
									
										
										
										
											2016-08-29 11:33:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 19:05:06 -08:00
										 |  |  |            dispatchEvent(required.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(minLength.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(maxLength.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(pattern.nativeElement, 'input'); | 
					
						
							| 
									
										
										
										
											2016-08-29 11:33:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 19:05:06 -08:00
										 |  |  |            const form = fixture.debugElement.children[0].injector.get(NgForm); | 
					
						
							|  |  |  |            expect(form.control.hasError('required', ['required'])).toEqual(false); | 
					
						
							|  |  |  |            expect(form.control.hasError('minlength', ['minlength'])).toEqual(false); | 
					
						
							|  |  |  |            expect(form.control.hasError('maxlength', ['maxlength'])).toEqual(false); | 
					
						
							|  |  |  |            expect(form.control.hasError('pattern', ['pattern'])).toEqual(false); | 
					
						
							|  |  |  |            expect(form.valid).toEqual(true); | 
					
						
							| 
									
										
										
										
											2018-11-06 14:02:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 19:05:06 -08:00
										 |  |  |            fixture.componentInstance.required = true; | 
					
						
							|  |  |  |            fixture.componentInstance.minLen = 3; | 
					
						
							|  |  |  |            fixture.componentInstance.maxLen = 3; | 
					
						
							|  |  |  |            fixture.componentInstance.pattern = '.{3,}'; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2018-11-06 14:02:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 19:05:06 -08:00
										 |  |  |            dispatchEvent(required.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(minLength.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(maxLength.nativeElement, 'input'); | 
					
						
							|  |  |  |            dispatchEvent(pattern.nativeElement, 'input'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(form.control.hasError('required', ['required'])).toEqual(true); | 
					
						
							|  |  |  |            expect(form.control.hasError('minlength', ['minlength'])).toEqual(true); | 
					
						
							|  |  |  |            expect(form.control.hasError('maxlength', ['maxlength'])).toEqual(true); | 
					
						
							|  |  |  |            expect(form.control.hasError('pattern', ['pattern'])).toEqual(true); | 
					
						
							|  |  |  |            expect(form.valid).toEqual(false); | 
					
						
							| 
									
										
										
										
											2018-11-06 14:02:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 19:05:06 -08:00
										 |  |  |            expect(required.nativeElement.getAttribute('required')).toEqual(''); | 
					
						
							|  |  |  |            expect(fixture.componentInstance.minLen.toString()) | 
					
						
							|  |  |  |                .toEqual(minLength.nativeElement.getAttribute('minlength')); | 
					
						
							|  |  |  |            expect(fixture.componentInstance.maxLen.toString()) | 
					
						
							|  |  |  |                .toEqual(maxLength.nativeElement.getAttribute('maxlength')); | 
					
						
							|  |  |  |            expect(fixture.componentInstance.pattern.toString()) | 
					
						
							|  |  |  |                .toEqual(pattern.nativeElement.getAttribute('pattern')); | 
					
						
							| 
									
										
										
										
											2018-11-06 14:02:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 19:05:06 -08:00
										 |  |  |            fixture.componentInstance.required = false; | 
					
						
							|  |  |  |            fixture.componentInstance.minLen = null !; | 
					
						
							|  |  |  |            fixture.componentInstance.maxLen = null !; | 
					
						
							|  |  |  |            fixture.componentInstance.pattern = null !; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(form.control.hasError('required', ['required'])).toEqual(false); | 
					
						
							|  |  |  |            expect(form.control.hasError('minlength', ['minlength'])).toEqual(false); | 
					
						
							|  |  |  |            expect(form.control.hasError('maxlength', ['maxlength'])).toEqual(false); | 
					
						
							|  |  |  |            expect(form.control.hasError('pattern', ['pattern'])).toEqual(false); | 
					
						
							|  |  |  |            expect(form.valid).toEqual(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(required.nativeElement.getAttribute('required')).toEqual(null); | 
					
						
							|  |  |  |            expect(required.nativeElement.getAttribute('minlength')).toEqual(null); | 
					
						
							|  |  |  |            expect(required.nativeElement.getAttribute('maxlength')).toEqual(null); | 
					
						
							|  |  |  |            expect(required.nativeElement.getAttribute('pattern')).toEqual(null); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2018-11-06 14:02:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-09 15:07:50 -08:00
										 |  |  |       it('should update control status', fakeAsync(() => { | 
					
						
							|  |  |  |            const fixture = initTest(NgModelChangeState); | 
					
						
							|  |  |  |            const inputEl = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  |            const inputNativeEl = inputEl.nativeElement; | 
					
						
							|  |  |  |            const onNgModelChange = jasmine.createSpy('onNgModelChange'); | 
					
						
							|  |  |  |            fixture.componentInstance.onNgModelChange = onNgModelChange; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2018-11-06 14:02:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-09 15:07:50 -08:00
										 |  |  |            expect(onNgModelChange).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2018-11-06 14:02:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-09 15:07:50 -08:00
										 |  |  |            inputNativeEl.value = 'updated'; | 
					
						
							|  |  |  |            onNgModelChange.and.callFake((ngModel: NgModel) => { | 
					
						
							|  |  |  |              expect(ngModel.invalid).toBe(true); | 
					
						
							|  |  |  |              expect(ngModel.value).toBe('updated'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |            dispatchEvent(inputNativeEl, 'input'); | 
					
						
							|  |  |  |            expect(onNgModelChange).toHaveBeenCalled(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            inputNativeEl.value = '333'; | 
					
						
							|  |  |  |            onNgModelChange.and.callFake((ngModel: NgModel) => { | 
					
						
							|  |  |  |              expect(ngModel.invalid).toBe(false); | 
					
						
							|  |  |  |              expect(ngModel.value).toBe('333'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |            dispatchEvent(inputNativeEl, 'input'); | 
					
						
							|  |  |  |            expect(onNgModelChange).toHaveBeenCalledTimes(2); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2018-01-12 20:03:54 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-29 11:33:49 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.
However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.
As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:
```ts
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```
Or, if you want to change the mode  based on locale or platform,
you can use a factory:
```ts
import {shouldUseBuffering} from 'my/lib';
....
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```
Closes #15079.
PR Close #15256
											
										 
											2017-03-20 17:38:33 -07:00
										 |  |  |     describe('IME events', () => { | 
					
						
							|  |  |  |       it('should determine IME event handling depending on platform by default', fakeAsync(() => { | 
					
						
							|  |  |  |            const fixture = initTest(StandaloneNgModel); | 
					
						
							|  |  |  |            const inputEl = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  |            const inputNativeEl = inputEl.nativeElement; | 
					
						
							|  |  |  |            fixture.componentInstance.name = 'oldValue'; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  |            expect(inputNativeEl.value).toEqual('oldValue'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            inputEl.triggerEventHandler('compositionstart', null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            inputNativeEl.value = 'updatedValue'; | 
					
						
							|  |  |  |            dispatchEvent(inputNativeEl, 'input'); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const isAndroid = /android (\d+)/.test(getDOM().getUserAgent().toLowerCase()); | 
					
						
							|  |  |  |            if (isAndroid) { | 
					
						
							|  |  |  |              // On Android, values should update immediately
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name).toEqual('updatedValue'); | 
					
						
							|  |  |  |            } else { | 
					
						
							|  |  |  |              // On other platforms, values should wait until compositionend
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name).toEqual('oldValue'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              inputEl.triggerEventHandler('compositionend', {target: {value: 'updatedValue'}}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              fixture.detectChanges(); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(fixture.componentInstance.name).toEqual('updatedValue'); | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should hold IME events until compositionend if composition mode', fakeAsync(() => { | 
					
						
							|  |  |  |            TestBed.overrideComponent( | 
					
						
							|  |  |  |                StandaloneNgModel, | 
					
						
							|  |  |  |                {set: {providers: [{provide: COMPOSITION_BUFFER_MODE, useValue: true}]}}); | 
					
						
							|  |  |  |            const fixture = initTest(StandaloneNgModel); | 
					
						
							|  |  |  |            const inputEl = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  |            const inputNativeEl = inputEl.nativeElement; | 
					
						
							|  |  |  |            fixture.componentInstance.name = 'oldValue'; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  |            expect(inputNativeEl.value).toEqual('oldValue'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            inputEl.triggerEventHandler('compositionstart', null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            inputNativeEl.value = 'updatedValue'; | 
					
						
							|  |  |  |            dispatchEvent(inputNativeEl, 'input'); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // ngModel should not update when compositionstart
 | 
					
						
							|  |  |  |            expect(fixture.componentInstance.name).toEqual('oldValue'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            inputEl.triggerEventHandler('compositionend', {target: {value: 'updatedValue'}}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // ngModel should update when compositionend
 | 
					
						
							|  |  |  |            expect(fixture.componentInstance.name).toEqual('updatedValue'); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should work normally with composition events if composition mode is off', | 
					
						
							|  |  |  |          fakeAsync(() => { | 
					
						
							|  |  |  |            TestBed.overrideComponent( | 
					
						
							|  |  |  |                StandaloneNgModel, | 
					
						
							|  |  |  |                {set: {providers: [{provide: COMPOSITION_BUFFER_MODE, useValue: false}]}}); | 
					
						
							|  |  |  |            const fixture = initTest(StandaloneNgModel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const inputEl = fixture.debugElement.query(By.css('input')); | 
					
						
							|  |  |  |            const inputNativeEl = inputEl.nativeElement; | 
					
						
							|  |  |  |            fixture.componentInstance.name = 'oldValue'; | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  |            expect(inputNativeEl.value).toEqual('oldValue'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            inputEl.triggerEventHandler('compositionstart', null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            inputNativeEl.value = 'updatedValue'; | 
					
						
							|  |  |  |            dispatchEvent(inputNativeEl, 'input'); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // ngModel should update normally
 | 
					
						
							|  |  |  |            expect(fixture.componentInstance.name).toEqual('updatedValue'); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  |     describe('ngModel corner cases', () => { | 
					
						
							|  |  |  |       it('should update the view when the model is set back to what used to be in the view', | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |          fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(StandaloneNgModel); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.name = ''; | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            const input = fixture.debugElement.query(By.css('input')).nativeElement; | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  |            input.value = 'aa'; | 
					
						
							|  |  |  |            input.selectionStart = 1; | 
					
						
							|  |  |  |            dispatchEvent(input, 'input'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            expect(fixture.componentInstance.name).toEqual('aa'); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |            // Programmatically update the input value to be "bb".
 | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.name = 'bb'; | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  |            expect(input.value).toEqual('bb'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Programatically set it back to "aa".
 | 
					
						
							| 
									
										
										
										
											2016-09-09 12:04:38 -07:00
										 |  |  |            fixture.componentInstance.name = 'aa'; | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  |            fixture.detectChanges(); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  |            expect(input.value).toEqual('aa'); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       it('should not crash when validity is checked from a binding', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-12-16 02:07:26 +01:00
										 |  |  |            const fixture = initTest(NgModelValidBinding); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  |            tick(); | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |            expect(() => fixture.detectChanges()).not.toThrowError(); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-10-19 18:56:31 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-07-25 15:57:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'standalone-ng-model', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							|  |  |  |     <input type="text" [(ngModel)]="name"> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class StandaloneNgModel { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   name !: string; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-form', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							| 
									
										
										
										
											2016-10-11 23:49:36 +01:00
										 |  |  |     <form (ngSubmit)="event=$event" (reset)="onReset()"> | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       <input name="name" [(ngModel)]="name" minlength="10" [ngModelOptions]="options"> | 
					
						
							|  |  |  |     </form> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelForm { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |   name !: string | null; | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   event !: Event; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |   options = {}; | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   onReset() {} | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-21 03:36:48 +03:00
										 |  |  | @Component({selector: 'ng-model-native-validate-form', template: `<form ngNativeValidate></form>`}) | 
					
						
							|  |  |  | class NgModelNativeValidateForm { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-group-form', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							|  |  |  |     <form> | 
					
						
							|  |  |  |       <div ngModelGroup="name"> | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  |         <input name="first" [(ngModel)]="first" required [disabled]="isDisabled"> | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |         <input name="last" [(ngModel)]="last"> | 
					
						
							|  |  |  |       </div> | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |       <input name="email" [(ngModel)]="email" [ngModelOptions]="options"> | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |     </form> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelGroupForm { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   first !: string; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   last !: string; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   email !: string; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   isDisabled !: boolean; | 
					
						
							| 
									
										
										
										
											2017-08-07 21:11:46 -07:00
										 |  |  |   options = {updateOn: 'change'}; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @Component({ | 
					
						
							| 
									
										
										
										
											2016-08-24 16:58:43 -07:00
										 |  |  |   selector: 'ng-model-valid-binding', | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |   template: `
 | 
					
						
							|  |  |  |     <form> | 
					
						
							|  |  |  |       <div ngModelGroup="name" #group="ngModelGroup"> | 
					
						
							|  |  |  |         <input name="first" [(ngModel)]="first" required> | 
					
						
							|  |  |  |         {{ group.valid }} | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     </form> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelValidBinding { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   first !: string; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-ngif-form', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							|  |  |  |     <form> | 
					
						
							|  |  |  |       <div ngModelGroup="name" *ngIf="groupShowing"> | 
					
						
							|  |  |  |         <input name="first" [(ngModel)]="first"> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |       <input name="email" [(ngModel)]="email" *ngIf="emailShowing"> | 
					
						
							|  |  |  |     </form> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelNgIfForm { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   first !: string; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |   groupShowing = true; | 
					
						
							|  |  |  |   emailShowing = true; | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   email !: string; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-no-form', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							|  |  |  |     <form ngNoForm> | 
					
						
							|  |  |  |       <input name="name"> | 
					
						
							|  |  |  |     </form> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgNoFormComp { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'invalid-ng-model-noname', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							|  |  |  |     <form> | 
					
						
							|  |  |  |       <input [(ngModel)]="name"> | 
					
						
							|  |  |  |     </form> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class InvalidNgModelNoName { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-options-standalone', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							| 
									
										
										
										
											2017-08-08 14:37:29 -07:00
										 |  |  |     <form [ngFormOptions]="formOptions"> | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |       <input name="one" [(ngModel)]="one"> | 
					
						
							| 
									
										
										
										
											2017-08-08 14:37:29 -07:00
										 |  |  |       <input [(ngModel)]="two" [ngModelOptions]="options"> | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  |     </form> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelOptionsStandalone { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   one !: string; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   two !: string; | 
					
						
							| 
									
										
										
										
											2017-08-08 14:37:29 -07:00
										 |  |  |   options: {name?: string, standalone?: boolean, updateOn?: string} = {standalone: true}; | 
					
						
							|  |  |  |   formOptions = {}; | 
					
						
							| 
									
										
										
										
											2016-08-15 16:37:59 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-29 11:33:49 -07:00
										 |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-validation-bindings', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							|  |  |  |     <form> | 
					
						
							|  |  |  |       <input name="required" ngModel  [required]="required"> | 
					
						
							|  |  |  |       <input name="minlength" ngModel  [minlength]="minLen"> | 
					
						
							|  |  |  |       <input name="maxlength" ngModel [maxlength]="maxLen"> | 
					
						
							|  |  |  |       <input name="pattern" ngModel  [pattern]="pattern"> | 
					
						
							|  |  |  |     </form> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelValidationBindings { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   required !: boolean; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   minLen !: number; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   maxLen !: number; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   pattern !: string; | 
					
						
							| 
									
										
										
										
											2016-08-29 11:33:49 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-10 18:17:45 +02:00
										 |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-multiple-validators', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							|  |  |  |     <form> | 
					
						
							|  |  |  |       <input name="tovalidate" ngModel  [required]="required" [minlength]="minLen" [pattern]="pattern"> | 
					
						
							|  |  |  |     </form> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelMultipleValidators { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   required !: boolean; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   minLen !: number; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   pattern !: string | RegExp; | 
					
						
							| 
									
										
										
										
											2016-10-10 18:17:45 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-10 13:44:04 +03:00
										 |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-checkbox-validator', | 
					
						
							|  |  |  |   template: | 
					
						
							|  |  |  |       `<form><input type="checkbox" [(ngModel)]="accepted" [required]="required" name="checkbox"></form>` | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelCheckboxRequiredValidator { | 
					
						
							|  |  |  |   accepted: boolean = false; | 
					
						
							|  |  |  |   required: boolean = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-29 20:07:02 +03:00
										 |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-email', | 
					
						
							|  |  |  |   template: `<form><input type="email" ngModel [email]="validatorEnabled" name="email"></form>` | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelEmailValidator { | 
					
						
							|  |  |  |   validatorEnabled: boolean = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:56:31 +02:00
										 |  |  | @Directive({ | 
					
						
							|  |  |  |   selector: '[ng-async-validator]', | 
					
						
							|  |  |  |   providers: [ | 
					
						
							|  |  |  |     {provide: NG_ASYNC_VALIDATORS, useExisting: forwardRef(() => NgAsyncValidator), multi: true} | 
					
						
							|  |  |  |   ] | 
					
						
							|  |  |  | }) | 
					
						
							| 
									
										
										
										
											2017-02-21 03:26:51 +03:00
										 |  |  | class NgAsyncValidator implements AsyncValidator { | 
					
						
							| 
									
										
										
										
											2016-10-19 18:56:31 +02:00
										 |  |  |   validate(c: AbstractControl) { return Promise.resolve(null); } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-async-validation', | 
					
						
							|  |  |  |   template: `<input name="async" ngModel ng-async-validator>` | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelAsyncValidation { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 02:54:36 -08:00
										 |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-changes-form', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							|  |  |  |     <form> | 
					
						
							| 
									
										
										
										
											2018-08-01 07:17:58 +02:00
										 |  |  |       <input name="async" [ngModel]="name" (ngModelChange)="log()" | 
					
						
							| 
									
										
										
										
											2017-11-11 02:54:36 -08:00
										 |  |  |              [ngModelOptions]="options"> | 
					
						
							|  |  |  |     </form> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelChangesForm { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   name !: string; | 
					
						
							| 
									
										
										
										
											2017-11-11 02:54:36 -08:00
										 |  |  |   events: string[] = []; | 
					
						
							|  |  |  |   options: any; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   log() { this.events.push('fired'); } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-12 20:03:54 -08:00
										 |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'ng-model-change-state', | 
					
						
							|  |  |  |   template: `
 | 
					
						
							|  |  |  |     <input #ngModel="ngModel" ngModel [maxlength]="4" | 
					
						
							|  |  |  |            (ngModelChange)="onNgModelChange(ngModel)"> | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class NgModelChangeState { | 
					
						
							|  |  |  |   onNgModelChange = () => {}; | 
					
						
							|  |  |  | } |