Skip to content

Commit

Permalink
feat(forms): add hasError and getError to AbstractControlDirective
Browse files Browse the repository at this point in the history
Allows cleaner expressions in template-driven forms.

Before:

    <label>Username</label><input name="username" ngModel required #username="ngModel">
    <div *ngIf="username.dirty && username.control.hasError('required')">Username is required</div>

After:

    <label>Username</label><input name="username" ngModel required #username="ngModel">
    <div *ngIf="username.dirty && username.hasError('required')">Username is required</div>

Fixes angular#7255
  • Loading branch information
cexbrayat committed Oct 13, 2016
1 parent 36bc2ff commit 6c8c17e
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
66 changes: 65 additions & 1 deletion modules/@angular/forms/test/directives_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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';
Expand Down Expand Up @@ -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'));
});
});
});
}
2 changes: 2 additions & 0 deletions tools/public_api_guard/forms/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ export declare abstract class AbstractControlDirective {
valid: boolean;
value: any;
valueChanges: Observable<any>;
getError(errorCode: string, path?: string[]): any;
hasError(errorCode: string, path?: string[]): boolean;
reset(value?: any): void;
}

Expand Down

0 comments on commit 6c8c17e

Please sign in to comment.