feat(forms): add hasError and getError to AbstractControlDirective (#11985)
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 #7255
This commit is contained in:
parent
24facdea2d
commit
592f40aa9c
@ -57,4 +57,12 @@ export abstract class AbstractControlDirective {
|
|||||||
reset(value: any = undefined): void {
|
reset(value: any = undefined): void {
|
||||||
if (isPresent(this.control)) this.control.reset(value);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,15 @@ export function main() {
|
|||||||
expect(form.valueChanges).toBe(formModel.valueChanges);
|
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', () => {
|
describe('addControl', () => {
|
||||||
it('should throw when no control found', () => {
|
it('should throw when no control found', () => {
|
||||||
const dir = new FormControlName(form, null, null, [defaultAccessor]);
|
const dir = new FormControlName(form, null, null, [defaultAccessor]);
|
||||||
@ -329,6 +338,15 @@ export function main() {
|
|||||||
expect(form.enabled).toBe(formModel.enabled);
|
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', () => {
|
describe('addControl & addFormGroup', () => {
|
||||||
it('should create a control with the given name', fakeAsync(() => {
|
it('should create a control with the given name', fakeAsync(() => {
|
||||||
form.addFormGroup(personControlGroupDir);
|
form.addFormGroup(personControlGroupDir);
|
||||||
@ -406,6 +424,15 @@ export function main() {
|
|||||||
expect(controlGroupDir.disabled).toBe(formModel.disabled);
|
expect(controlGroupDir.disabled).toBe(formModel.disabled);
|
||||||
expect(controlGroupDir.enabled).toBe(formModel.enabled);
|
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', () => {
|
describe('FormArrayName', () => {
|
||||||
@ -434,6 +461,15 @@ export function main() {
|
|||||||
expect(formArrayDir.disabled).toBe(formModel.disabled);
|
expect(formArrayDir.disabled).toBe(formModel.disabled);
|
||||||
expect(formArrayDir.enabled).toBe(formModel.enabled);
|
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', () => {
|
describe('FormControlDirective', () => {
|
||||||
@ -466,6 +502,15 @@ export function main() {
|
|||||||
|
|
||||||
it('should reexport control properties', () => { checkProperties(control); });
|
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', () => {
|
it('should reexport new control properties', () => {
|
||||||
var newControl = new FormControl(null);
|
var newControl = new FormControl(null);
|
||||||
controlDir.form = newControl;
|
controlDir.form = newControl;
|
||||||
@ -486,15 +531,16 @@ export function main() {
|
|||||||
|
|
||||||
describe('NgModel', () => {
|
describe('NgModel', () => {
|
||||||
let ngModel: NgModel;
|
let ngModel: NgModel;
|
||||||
|
let control: FormControl;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ngModel = new NgModel(
|
ngModel = new NgModel(
|
||||||
null, [Validators.required], [asyncValidator('expected')], [defaultAccessor]);
|
null, [Validators.required], [asyncValidator('expected')], [defaultAccessor]);
|
||||||
ngModel.valueAccessor = new DummyControlValueAccessor();
|
ngModel.valueAccessor = new DummyControlValueAccessor();
|
||||||
|
control = ngModel.control;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reexport control properties', () => {
|
it('should reexport control properties', () => {
|
||||||
var control = ngModel.control;
|
|
||||||
expect(ngModel.control).toBe(control);
|
expect(ngModel.control).toBe(control);
|
||||||
expect(ngModel.value).toBe(control.value);
|
expect(ngModel.value).toBe(control.value);
|
||||||
expect(ngModel.valid).toBe(control.valid);
|
expect(ngModel.valid).toBe(control.valid);
|
||||||
@ -511,6 +557,15 @@ export function main() {
|
|||||||
expect(ngModel.enabled).toBe(control.enabled);
|
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', () => {
|
it('should throw when no value accessor with named control', () => {
|
||||||
const namedDir = new NgModel(null, null, null, null);
|
const namedDir = new NgModel(null, null, null, null);
|
||||||
namedDir.name = 'one';
|
namedDir.name = 'one';
|
||||||
@ -610,6 +665,15 @@ export function main() {
|
|||||||
expect(controlNameDir.disabled).toBe(formModel.disabled);
|
expect(controlNameDir.disabled).toBe(formModel.disabled);
|
||||||
expect(controlNameDir.enabled).toBe(formModel.enabled);
|
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
tools/public_api_guard/forms/index.d.ts
vendored
2
tools/public_api_guard/forms/index.d.ts
vendored
@ -84,6 +84,8 @@ export declare abstract class AbstractControlDirective {
|
|||||||
valid: boolean;
|
valid: boolean;
|
||||||
value: any;
|
value: any;
|
||||||
valueChanges: Observable<any>;
|
valueChanges: Observable<any>;
|
||||||
|
getError(errorCode: string, path?: string[]): any;
|
||||||
|
hasError(errorCode: string, path?: string[]): boolean;
|
||||||
reset(value?: any): void;
|
reset(value?: any): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user