Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 28x 1x 34x 34x 42x 9x 33x 33x 33x 93x 45x 48x 48x 33x 33x 15x | /**
* Copyright (c) Siemens 2016 - 2026
* SPDX-License-Identifier: MIT
*/
import { inject, Injectable } from '@angular/core';
import { ValidationErrors } from '@angular/forms';
import { t } from '@siemens/element-translate-ng/translate';
import { SiFormError } from './si-form-item/si-form-item.component';
import { SiFormValidationErrorMapper } from './si-form-validation-error.model';
/**
* Creates the map of default error resolver.
* This is a function as $localize requires an injection context.
*
* @internal
*/
export const buildDefaults = (): SiFormValidationErrorMapper => ({
// Phone number specific
notSupportedPhoneNumberCountry: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.PHONE_COUNTRY:Unsupported country/region code`
),
invalidPhoneNumberFormat: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.INVALID_PHONE:Invalid phone number`
),
// IP address specific
ipv4Address: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.IPV4:Invalid IPv4 address`),
ipv6Address: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.IPV6:Invalid IPv6 address`),
// Min / max
max: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.MAX:Max. {{max}}`),
min: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.MIN:Min. {{min}}`),
maxlength: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.MAX_LENGTH:Max. {{requiredLength}} characters`
),
minlength: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.MIN_LENGTH:Min. {{requiredLength}} characters`
),
// Date specific
dateFormat: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.DATE_FORMAT:Invalid date`),
endBeforeStart: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.END_BEFORE_START:End date before start date`
),
invalidEndDateFormat: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.DATE_FORMAT_END:Invalid end date`
),
invalidStartDateFormat: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.DATE_FORMAT_START:Invalid start date`
),
maxDate: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.MAX_DATE:Date prior to {{maxString}} required`
),
minDate: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.MIN_DATE:Date after {{minString}} required`
),
maxTime: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.MAX_TIME:Time prior to {{maxString}} required`
),
minTime: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.MIN_TIME:Time after {{minString}} required`
),
rangeAfterMaxDate: t(
() =>
$localize`:@@SI_FORM_CONTAINER.ERROR.RANGE_AFTER_MAX_DATE:Period prior to {{maxString}} required`
),
rangeBeforeMinDate: t(
() =>
$localize`:@@SI_FORM_CONTAINER.ERROR.RANGE_BEFORE_MIN_DATE:Period after {{minString}} required`
),
// Time units
hours: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.HOURS:Integer between 0 and {{max}} required`
),
minutes: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.MINUTES:Integer between 0 and 59 required`),
seconds: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.SECONDS:Integer between 0 and 59 required`),
milliseconds: t(
() => $localize`:@@SI_FORM_CONTAINER.ERROR.MILLISECONDS:Integer between 0 and 999 required`
),
// Various
email: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.EMAIL:Invalid email address`),
numberFormat: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.NUMBER_FORMAT:Number required`),
pattern: t(
() =>
$localize`:@@SI_FORM_CONTAINER.ERROR.PATTERN:The value does not match the predefined pattern.`
),
required: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.REQUIRED:Required`),
requiredTrue: t(() => $localize`:@@SI_FORM_CONTAINER.ERROR.REQUIRED_TRUE:Required`)
});
/**
* A service to resolve the validation error of an Angular control to a message or translation key.
*
* It can be provided using {@link provideFormValidationErrorMapper}.
* If not provided, there will be a default instance in the root injector using only the default keys.
*
* There can be multiple instances to support providing in a lazy loaded module.
* If the service cannot find a message, it will try to resolve it using a parent service if available.
*
* @internal
*/
@Injectable({
providedIn: 'root',
useFactory: () => new SiFormValidationErrorService(buildDefaults())
})
export class SiFormValidationErrorService {
private readonly parent = inject(SiFormValidationErrorService, {
optional: true,
skipSelf: true
});
// eslint-disable-next-line @angular-eslint/prefer-inject
constructor(private errorMapper: SiFormValidationErrorMapper) {}
/**
* Resolves the provided form errors to a list of {@link SiFormError}.
* To resolution order is:
* 1. componentMapper
* 2. containerMapper using the controlName
* 3. containerMapper without controlName
* 4. errorMapper of the service using the controlName
* 5. errorMapper of the service
* 6: parent service
*/
resolveErrors(
controlName: string | number | null | undefined,
errors: ValidationErrors | null,
componentMapper?: SiFormValidationErrorMapper,
containerMapper?: SiFormValidationErrorMapper
): SiFormError[] {
if (!errors) {
return [];
}
/*
* Converts the angular error object (like: {required: true, minLength: {actualLength: 1, requiredLength: 3}})
* to SiFormError[].
* Therefore, the error key is look up in the error mappers.
* If it can be resolved, the error will be printed using the resolved text.
*/
return Object.entries(errors).map(([key, params]) =>
this.resolveError(key, controlName, params, componentMapper, containerMapper)
);
}
private resolveError(
key: string,
controlName: string | number | null | undefined,
params: any,
componentMapper?: SiFormValidationErrorMapper,
containerMapper?: SiFormValidationErrorMapper
): SiFormError {
return (
this.resolveMessage(key, controlName, params, componentMapper) ??
this.resolveMessage(key, controlName, params, containerMapper) ??
this.resolveMessage(key, controlName, params, this.errorMapper) ??
this.parent?.resolveError(key, controlName, params) ?? { key, params }
);
}
private resolveMessage(
key: string,
controlName: string | number | null | undefined,
params: any,
mapper?: SiFormValidationErrorMapper
): SiFormError | undefined {
if (!mapper) {
return undefined;
}
const resolver = mapper[`${controlName}.${key}`] ?? mapper[key];
if (resolver) {
const message = typeof resolver === 'function' ? resolver(params) : resolver;
return message ? { key, message, params } : undefined;
}
return undefined;
}
}
|