Skip to content

Commit

Permalink
fixup! fix(forms): improve error message for invalid value accessors
Browse files Browse the repository at this point in the history
  • Loading branch information
ameryousuf committed Mar 13, 2022
1 parent c104e66 commit 65ed10d
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 21 deletions.
40 changes: 20 additions & 20 deletions packages/forms/src/directives/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {FormArrayName} from './reactive_directives/form_group_name';
import {ngModelWarning} from './reactive_errors';
import {AsyncValidatorFn, Validator, ValidatorFn} from './validators';


export function controlPath(name: string|null, parent: ControlContainer): string[] {
return [...parent.path!, name!];
}
Expand Down Expand Up @@ -88,7 +87,7 @@ export function cleanUpControl(
}

function registerOnValidatorChange<V>(validators: (V|Validator)[], onChange: () => void): void {
validators.forEach((validator: (V|Validator)) => {
validators.forEach((validator: V|Validator) => {
if ((<Validator>validator).registerOnValidatorChange)
(<Validator>validator).registerOnValidatorChange!(onChange);
});
Expand Down Expand Up @@ -169,7 +168,7 @@ export function cleanUpValidators(
const validators = getControlValidators(control);
if (Array.isArray(validators) && validators.length > 0) {
// Filter out directive validator function.
const updatedValidators = validators.filter(validator => validator !== dir.validator);
const updatedValidators = validators.filter((validator) => validator !== dir.validator);
if (updatedValidators.length !== validators.length) {
isControlUpdated = true;
control.setValidators(updatedValidators);
Expand All @@ -182,7 +181,7 @@ export function cleanUpValidators(
if (Array.isArray(asyncValidators) && asyncValidators.length > 0) {
// Filter out directive async validator function.
const updatedAsyncValidators =
asyncValidators.filter(asyncValidator => asyncValidator !== dir.asyncValidator);
asyncValidators.filter((asyncValidator) => asyncValidator !== dir.asyncValidator);
if (updatedAsyncValidators.length !== asyncValidators.length) {
isControlUpdated = true;
control.setAsyncValidators(updatedAsyncValidators);
Expand Down Expand Up @@ -272,18 +271,23 @@ function _noControlError(dir: NgControl) {
return _throwError(dir, 'There is no FormControl instance attached to form control element with');
}

function _throwError(dir: AbstractControlDirective, message: string, extraMessage?: string): void {
let messageEnd: string;
if (dir.path!.length > 1) {
messageEnd = `path: '${dir.path!.join(' -> ')}'`;
} else if (dir.path![0]) {
messageEnd = `name: '${dir.path}'`;
} else {
messageEnd = 'unspecified name attribute.';
}
function _throwError(dir: AbstractControlDirective, message: string): void {
const messageEnd = _describeControlLocation(dir);
throw new Error(`${message} ${messageEnd}`);
}

extraMessage = extraMessage ? '\n' + extraMessage : '';
throw new Error(`${message} ${messageEnd}${extraMessage}`);
function _describeControlLocation(dir: AbstractControlDirective): string {
const path = dir.path;
if (path && path.length > 1) return `path: '${path.join(' -> ')}'`;
if (path?.[0]) return `name: '${path}'`;
return 'unspecified name attribute';
}

function _throwInvalidValueAccessorError(dir: AbstractControlDirective) {
const loc = _describeControlLocation(dir);
throw new Error(
`Value accessor was not provided as an array for form control with ${loc}. ` +
`Check that the \`NG_VALUE_ACCESSOR\` token is configured as a \`multi: true\` provider.`);
}

export function isPropertyUpdated(changes: {[key: string]: any}, viewModel: any): boolean {
Expand Down Expand Up @@ -317,9 +321,7 @@ export function selectValueAccessor(
if (!valueAccessors) return null;

if (!Array.isArray(valueAccessors) && (typeof ngDevMode === 'undefined' || ngDevMode))
_throwError(
dir, 'Value accessor was not provided as an array for form control with',
'Please make sure that the `NG_VALUE_ACCESSOR` token is configured as a multi provider (with the `multi: true` property).');
_throwInvalidValueAccessorError(dir);

let defaultAccessor: ControlValueAccessor|undefined = undefined;
let builtinAccessor: ControlValueAccessor|undefined = undefined;
Expand All @@ -328,12 +330,10 @@ export function selectValueAccessor(
valueAccessors.forEach((v: ControlValueAccessor) => {
if (v.constructor === DefaultValueAccessor) {
defaultAccessor = v;

} else if (isBuiltInAccessor(v)) {
if (builtinAccessor && (typeof ngDevMode === 'undefined' || ngDevMode))
_throwError(dir, 'More than one built-in value accessor matches form control with');
builtinAccessor = v;

} else {
if (customAccessor && (typeof ngDevMode === 'undefined' || ngDevMode))
_throwError(dir, 'More than one custom value accessor matches form control with');
Expand Down
2 changes: 1 addition & 1 deletion packages/forms/test/directives_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class CustomValidatorDirective implements Validator {
it('should throw when accessor is not provided as array', () => {
expect(() => selectValueAccessor(dir, {} as any[]))
.toThrowError(
'Value accessor was not provided as an array for form control with unspecified name attribute.\nPlease make sure that the `NG_VALUE_ACCESSOR` token is configured as a multi provider (with the `multi: true` property).');
'Value accessor was not provided as an array for form control with unspecified name attribute. Check that the \`NG_VALUE_ACCESSOR\` token is configured as a \`multi: true\` provider.');
});

it('should return the default value accessor when no other provided', () => {
Expand Down

0 comments on commit 65ed10d

Please sign in to comment.