diff --git a/modules/@angular/forms/src/directives.ts b/modules/@angular/forms/src/directives.ts index 5010b3cf36..f6e3719d4a 100644 --- a/modules/@angular/forms/src/directives.ts +++ b/modules/@angular/forms/src/directives.ts @@ -14,6 +14,7 @@ import {NgControlStatus, NgControlStatusGroup} from './directives/ng_control_sta import {NgForm} from './directives/ng_form'; import {NgModel} from './directives/ng_model'; import {NgModelGroup} from './directives/ng_model_group'; +import {NgNovalidate} from './directives/ng_novalidate_directive'; import {NumberValueAccessor} from './directives/number_value_accessor'; import {RadioControlValueAccessor} from './directives/radio_control_value_accessor'; import {RangeValueAccessor} from './directives/range_value_accessor'; @@ -47,7 +48,7 @@ export {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValida export const SHARED_FORM_DIRECTIVES: Type[] = [ NgSelectOption, NgSelectMultipleOption, DefaultValueAccessor, NumberValueAccessor, RangeValueAccessor, CheckboxControlValueAccessor, SelectControlValueAccessor, - SelectMultipleControlValueAccessor, RadioControlValueAccessor, NgControlStatus, + SelectMultipleControlValueAccessor, RadioControlValueAccessor, NgControlStatus, NgNovalidate, NgControlStatusGroup, RequiredValidator, MinLengthValidator, MaxLengthValidator, PatternValidator ]; diff --git a/modules/@angular/forms/src/directives/ng_novalidate_directive.ts b/modules/@angular/forms/src/directives/ng_novalidate_directive.ts new file mode 100644 index 0000000000..72228a1b8c --- /dev/null +++ b/modules/@angular/forms/src/directives/ng_novalidate_directive.ts @@ -0,0 +1,16 @@ +/** + * @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 + */ + +import {Directive} from '@angular/core'; + +@Directive({ + selector: 'form:not([ngNoForm])', + host: {'novalidate': ''}, +}) +export class NgNovalidate { +} diff --git a/modules/@angular/forms/test/reactive_integration_spec.ts b/modules/@angular/forms/test/reactive_integration_spec.ts index bcdfc637fb..54b1ccab8c 100644 --- a/modules/@angular/forms/test/reactive_integration_spec.ts +++ b/modules/@angular/forms/test/reactive_integration_spec.ts @@ -71,6 +71,15 @@ export function main() { expect(input.nativeElement.value).toEqual('loginValue'); }); + it('should add novalidate by default to form', () => { + const fixture = TestBed.createComponent(FormGroupComp); + fixture.componentInstance.form = new FormGroup({'login': new FormControl('loginValue')}); + fixture.detectChanges(); + + const form = fixture.debugElement.query(By.css('form')); + expect(form.nativeElement.getAttribute('novalidate')).toEqual(''); + }); + it('work with formGroups (view -> model)', () => { const fixture = TestBed.createComponent(FormGroupComp); const form = new FormGroup({'login': new FormControl('oldValue')}); diff --git a/modules/@angular/forms/test/template_integration_spec.ts b/modules/@angular/forms/test/template_integration_spec.ts index 48d074f91c..41e22a918b 100644 --- a/modules/@angular/forms/test/template_integration_spec.ts +++ b/modules/@angular/forms/test/template_integration_spec.ts @@ -61,6 +61,16 @@ export function main() { expect(form.valid).toBe(false); })); + it('should add novalidate by default to form element', fakeAsync(() => { + const fixture = TestBed.createComponent(NgModelForm); + + fixture.detectChanges(); + tick(); + + const form = fixture.debugElement.query(By.css('form')); + expect(form.nativeElement.getAttribute('novalidate')).toEqual(''); + })); + it('should support ngModelGroup', fakeAsync(() => { const fixture = TestBed.createComponent(NgModelGroupForm); fixture.componentInstance.first = 'Nancy'; @@ -217,6 +227,13 @@ export function main() { fixture.detectChanges(); expect(fixture.debugElement.children[0].providerTokens.length).toEqual(0); }); + + it('should not add novalidate when ngNoForm is used', () => { + const fixture = TestBed.createComponent(NgNoFormComp); + fixture.detectChanges(); + const form = fixture.debugElement.query(By.css('form')); + expect(form.nativeElement.hasAttribute('novalidate')).toBeFalsy(); + }); }); describe('name and ngModelOptions', () => {