,
27 | } as ErrorTemplate;
28 |
29 | it('should return true if the value is the same', () => {
30 | expect(distinctUntilErrorChanged(undefined, undefined)).toBeTrue();
31 | expect(distinctUntilErrorChanged(minError, minError)).toBeTrue();
32 | expect(
33 | distinctUntilErrorChanged(minErrorTemplate, minErrorTemplate)
34 | ).toBeTrue();
35 | });
36 |
37 | it('should return false if undefined follows other values', () => {
38 | expect(distinctUntilErrorChanged(minError, undefined)).toBeFalse();
39 | expect(distinctUntilErrorChanged(minErrorTemplate, undefined)).toBeFalse();
40 | });
41 |
42 | it('should return false if other values follow undefined', () => {
43 | expect(distinctUntilErrorChanged(undefined, minError)).toBeFalse();
44 | expect(distinctUntilErrorChanged(undefined, minErrorTemplate)).toBeFalse();
45 | });
46 |
47 | it('should return false if different values follow each other', () => {
48 | expect(distinctUntilErrorChanged(minError, maxError)).toBeFalse();
49 | expect(distinctUntilErrorChanged(maxError, maxErrorTemplate)).toBeFalse();
50 | expect(
51 | distinctUntilErrorChanged(maxErrorTemplate, minErrorTemplate)
52 | ).toBeFalse();
53 | expect(distinctUntilErrorChanged(minErrorTemplate, minError)).toBeFalse();
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/projects/ngx-mat-errors/src/lib/utils/distinct-until-error-changed.ts:
--------------------------------------------------------------------------------
1 | import type { ErrorTemplate } from '../types';
2 |
3 | export function distinctUntilErrorChanged(
4 | prev: P,
5 | curr: P
6 | ) {
7 | if (prev === curr) {
8 | return true;
9 | }
10 | if (!prev || !curr) {
11 | return false;
12 | }
13 | if (prev.template !== curr.template) {
14 | return false;
15 | }
16 | return prev.$implicit === curr.$implicit;
17 | }
18 |
--------------------------------------------------------------------------------
/projects/ngx-mat-errors/src/lib/utils/find-error-for-control.ts:
--------------------------------------------------------------------------------
1 | import type { AbstractControl } from '@angular/forms';
2 | import type { INgxMatErrorDef } from '../ngx-mat-error-def.directive';
3 | import { ErrorMessages } from '../types';
4 |
5 | /**
6 | * Finds the error key or custom error for a control.
7 | * @returns INgxMatErrorDef | undefined
8 | */
9 | export function findErrorForControl(
10 | control: AbstractControl,
11 | messages: ErrorMessages,
12 | customErrorMessages: readonly INgxMatErrorDef[]
13 | ) {
14 | const errorKeys = Object.keys(control.errors!);
15 | return (
16 | customErrorMessages.find((customErrorMessage) =>
17 | errorKeys.some((error) => {
18 | if (error !== customErrorMessage.ngxMatErrorDefFor) {
19 | return false;
20 | }
21 | return (
22 | !customErrorMessage.control || customErrorMessage.control === control
23 | );
24 | })
25 | ) ?? errorKeys.find((key) => key in messages)
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/projects/ngx-mat-errors/src/lib/utils/get-abstract-controls.ts:
--------------------------------------------------------------------------------
1 | import { coerceArray } from '@angular/cdk/coercion';
2 | import { AbstractControl, AbstractControlDirective } from '@angular/forms';
3 | import type { NgxMatErrorControls } from '../types';
4 |
5 | export function getAbstractControls(
6 | controls: NgxMatErrorControls
7 | ): AbstractControl[] | undefined {
8 | if (!controls) {
9 | return;
10 | }
11 | const _controls = coerceArray(controls)
12 | .map((control) =>
13 | !control
14 | ? undefined
15 | : control instanceof AbstractControlDirective
16 | ? control.control
17 | : control instanceof AbstractControl
18 | ? control
19 | : control.ngControl?.control
20 | )
21 | .filter((control: T): control is NonNullable => control != null);
22 | return _controls.length ? _controls : undefined;
23 | }
24 |
--------------------------------------------------------------------------------
/projects/ngx-mat-errors/src/lib/utils/get-control-with-error.ts:
--------------------------------------------------------------------------------
1 | import {
2 | StatusChangeEvent,
3 | ValueChangeEvent,
4 | type AbstractControl,
5 | } from '@angular/forms';
6 | import { combineLatest, filter, map, startWith, type Observable } from 'rxjs';
7 |
8 | export function getControlWithError(
9 | controls: AbstractControl[]
10 | ): Observable {
11 | const controlChanges = controls.map((control) =>
12 | control.events.pipe(
13 | filter(
14 | (event) =>
15 | event instanceof StatusChangeEvent ||
16 | event instanceof ValueChangeEvent
17 | ),
18 | startWith(null as any),
19 | map(() => control)
20 | )
21 | );
22 | return combineLatest(controlChanges).pipe(
23 | map((control) => control.find((control) => !!control.errors))
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/projects/ngx-mat-errors/src/public-api.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of ngx-mat-errors
3 | */
4 |
5 | export * from './lib/locales';
6 | export * from './lib/ngx-mat-error-def.directive';
7 | export * from './lib/ngx-mat-errors-for-date-range-picker.directive';
8 | export * from './lib/ngx-mat-errors.component';
9 | export * from './lib/ngx-mat-errors.module';
10 | export type * from './lib/types';
11 |
--------------------------------------------------------------------------------
/projects/ngx-mat-errors/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/lib",
5 | "declarationMap": true,
6 | "declaration": true,
7 | "inlineSources": true,
8 | "types": [],
9 | },
10 | "exclude": [
11 | "src/test.ts",
12 | "**/*.spec.ts"
13 | ],
14 | }
15 |
--------------------------------------------------------------------------------
/projects/ngx-mat-errors/tsconfig.lib.prod.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.lib.json",
3 | "compilerOptions": {
4 | "declarationMap": false
5 | },
6 | "angularCompilerOptions": {
7 | "compilationMode": "partial"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/projects/ngx-mat-errors/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/spec",
5 | "types": ["jasmine", "node"]
6 | },
7 | "include": ["**/*.spec.ts", "**/*.d.ts"]
8 | }
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist/out-tsc",
6 | "forceConsistentCasingInFileNames": true,
7 | "esModuleInterop": true,
8 | "strict": true,
9 | "noImplicitOverride": true,
10 | "noPropertyAccessFromIndexSignature": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "sourceMap": true,
14 | "paths": {
15 | "ngx-mat-errors": [
16 | "dist/ngx-mat-errors/ngx-mat-errors",
17 | "dist/ngx-mat-errors"
18 | ]
19 | },
20 | "declaration": false,
21 | "experimentalDecorators": true,
22 | "moduleResolution": "node",
23 | "importHelpers": true,
24 | "target": "ES2022",
25 | "module": "es2020",
26 | "lib": [
27 | "es2020",
28 | "dom"
29 | ],
30 | "useDefineForClassFields": false
31 | },
32 | "angularCompilerOptions": {
33 | "enableI18nLegacyMessageIdFormat": false,
34 | "strictInjectionParameters": true,
35 | "strictInputAccessModifiers": true,
36 | "strictTemplates": true
37 | }
38 | }
39 |
--------------------------------------------------------------------------------