From 592f40aa9c89265e59924d42f5a173d0803b8d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Exbrayat?= Date: Wed, 19 Oct 2016 18:49:02 +0200 Subject: [PATCH] feat(forms): add hasError and getError to AbstractControlDirective (#11985) Allows cleaner expressions in template-driven forms. Before:
Username is required
After:
Username is required
Fixes #7255 --- .../directives/abstract_control_directive.ts | 8 +++ .../@angular/forms/test/directives_spec.ts | 66 ++++++++++++++++++- tools/public_api_guard/forms/index.d.ts | 2 + 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/modules/@angular/forms/src/directives/abstract_control_directive.ts b/modules/@angular/forms/src/directives/abstract_control_directive.ts index ef3f1765f8..0e883f4d32 100644 --- a/modules/@angular/forms/src/directives/abstract_control_directive.ts +++ b/modules/@angular/forms/src/directives/abstract_control_directive.ts @@ -57,4 +57,12 @@ export abstract class AbstractControlDirective { reset(value: any = undefined): void { if (isPresent(this.control)) this.control.reset(value); } + + hasError(errorCode: string, path: string[] = null): boolean { + return isPresent(this.control) ? this.control.hasError(errorCode, path) : false; + } + + getError(errorCode: string, path: string[] = null): any { + return isPresent(this.control) ? this.control.getError(errorCode, path) : null; + } } diff --git a/modules/@angular/forms/test/directives_spec.ts b/modules/@angular/forms/test/directives_spec.ts index eb48c3fd69..1afd768850 100644 --- a/modules/@angular/forms/test/directives_spec.ts +++ b/modules/@angular/forms/test/directives_spec.ts @@ -158,6 +158,15 @@ export function main() { expect(form.valueChanges).toBe(formModel.valueChanges); }); + it('should reexport control methods', () => { + expect(form.hasError('required')).toBe(formModel.hasError('required')); + expect(form.getError('required')).toBe(formModel.getError('required')); + + formModel.setErrors({required: true}); + expect(form.hasError('required')).toBe(formModel.hasError('required')); + expect(form.getError('required')).toBe(formModel.getError('required')); + }); + describe('addControl', () => { it('should throw when no control found', () => { const dir = new FormControlName(form, null, null, [defaultAccessor]); @@ -329,6 +338,15 @@ export function main() { expect(form.enabled).toBe(formModel.enabled); }); + it('should reexport control methods', () => { + expect(form.hasError('required')).toBe(formModel.hasError('required')); + expect(form.getError('required')).toBe(formModel.getError('required')); + + formModel.setErrors({required: true}); + expect(form.hasError('required')).toBe(formModel.hasError('required')); + expect(form.getError('required')).toBe(formModel.getError('required')); + }); + describe('addControl & addFormGroup', () => { it('should create a control with the given name', fakeAsync(() => { form.addFormGroup(personControlGroupDir); @@ -406,6 +424,15 @@ export function main() { expect(controlGroupDir.disabled).toBe(formModel.disabled); expect(controlGroupDir.enabled).toBe(formModel.enabled); }); + + it('should reexport control methods', () => { + expect(controlGroupDir.hasError('required')).toBe(formModel.hasError('required')); + expect(controlGroupDir.getError('required')).toBe(formModel.getError('required')); + + formModel.setErrors({required: true}); + expect(controlGroupDir.hasError('required')).toBe(formModel.hasError('required')); + expect(controlGroupDir.getError('required')).toBe(formModel.getError('required')); + }); }); describe('FormArrayName', () => { @@ -434,6 +461,15 @@ export function main() { expect(formArrayDir.disabled).toBe(formModel.disabled); expect(formArrayDir.enabled).toBe(formModel.enabled); }); + + it('should reexport control methods', () => { + expect(formArrayDir.hasError('required')).toBe(formModel.hasError('required')); + expect(formArrayDir.getError('required')).toBe(formModel.getError('required')); + + formModel.setErrors({required: true}); + expect(formArrayDir.hasError('required')).toBe(formModel.hasError('required')); + expect(formArrayDir.getError('required')).toBe(formModel.getError('required')); + }); }); describe('FormControlDirective', () => { @@ -466,6 +502,15 @@ export function main() { it('should reexport control properties', () => { checkProperties(control); }); + it('should reexport control methods', () => { + expect(controlDir.hasError('required')).toBe(control.hasError('required')); + expect(controlDir.getError('required')).toBe(control.getError('required')); + + control.setErrors({required: true}); + expect(controlDir.hasError('required')).toBe(control.hasError('required')); + expect(controlDir.getError('required')).toBe(control.getError('required')); + }); + it('should reexport new control properties', () => { var newControl = new FormControl(null); controlDir.form = newControl; @@ -486,15 +531,16 @@ export function main() { describe('NgModel', () => { let ngModel: NgModel; + let control: FormControl; beforeEach(() => { ngModel = new NgModel( null, [Validators.required], [asyncValidator('expected')], [defaultAccessor]); ngModel.valueAccessor = new DummyControlValueAccessor(); + control = ngModel.control; }); it('should reexport control properties', () => { - var control = ngModel.control; expect(ngModel.control).toBe(control); expect(ngModel.value).toBe(control.value); expect(ngModel.valid).toBe(control.valid); @@ -511,6 +557,15 @@ export function main() { expect(ngModel.enabled).toBe(control.enabled); }); + it('should reexport control methods', () => { + expect(ngModel.hasError('required')).toBe(control.hasError('required')); + expect(ngModel.getError('required')).toBe(control.getError('required')); + + control.setErrors({required: true}); + expect(ngModel.hasError('required')).toBe(control.hasError('required')); + expect(ngModel.getError('required')).toBe(control.getError('required')); + }); + it('should throw when no value accessor with named control', () => { const namedDir = new NgModel(null, null, null, null); namedDir.name = 'one'; @@ -610,6 +665,15 @@ export function main() { expect(controlNameDir.disabled).toBe(formModel.disabled); expect(controlNameDir.enabled).toBe(formModel.enabled); }); + + it('should reexport control methods', () => { + expect(controlNameDir.hasError('required')).toBe(formModel.hasError('required')); + expect(controlNameDir.getError('required')).toBe(formModel.getError('required')); + + formModel.setErrors({required: true}); + expect(controlNameDir.hasError('required')).toBe(formModel.hasError('required')); + expect(controlNameDir.getError('required')).toBe(formModel.getError('required')); + }); }); }); } diff --git a/tools/public_api_guard/forms/index.d.ts b/tools/public_api_guard/forms/index.d.ts index 29174a048e..4e8daf43ea 100644 --- a/tools/public_api_guard/forms/index.d.ts +++ b/tools/public_api_guard/forms/index.d.ts @@ -84,6 +84,8 @@ export declare abstract class AbstractControlDirective { valid: boolean; value: any; valueChanges: Observable; + getError(errorCode: string, path?: string[]): any; + hasError(errorCode: string, path?: string[]): boolean; reset(value?: any): void; }