Created
July 5, 2024 12:07
-
-
Save dougal83/90d0ce1c23c9b2d3c06e17499ab0729a to your computer and use it in GitHub Desktop.
Directive for <mat-error> to generate default messages and convenience for custom.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable @typescript-eslint/no-unused-vars */ | |
/* eslint-disable @typescript-eslint/no-explicit-any */ | |
import { InjectionToken } from '@angular/core'; | |
const defaultErrors: { | |
[key: string]: any; | |
} = { | |
min: ({ minimum, actual }: any) => `Value must be at least ${minimum}`, | |
max: ({ maximum, actual }: any) => `Value must be less than ${maximum}`, | |
required: () => `This field is required`, | |
requiredtrue: () => `This field is required to be true`, | |
email: () => `Must be a valid email`, | |
minlength: ({ requiredLength, actualLength }: any) => | |
`Must be at least ${requiredLength} characters long`, | |
maxlength: ({ requiredLength, actualLength }: any) => | |
`Must be less than ${requiredLength} characters long`, | |
pattern: ({ pattern }: any) => `Value must match pattern`, | |
}; | |
export const DEFAULT_FORM_ERRORS = new InjectionToken('DEFAULT_FORM_ERRORS', { | |
providedIn: 'root', | |
factory: () => defaultErrors, | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { AsyncPipe } from '@angular/common'; | |
import { | |
AfterViewInit, | |
ChangeDetectionStrategy, | |
Component, | |
Input, | |
OnDestroy, | |
inject, | |
} from '@angular/core'; | |
import { ValidationErrors } from '@angular/forms'; | |
import { MatFormField } from '@angular/material/form-field'; | |
import { BehaviorSubject, Subscription, filter } from 'rxjs'; | |
import { DEFAULT_FORM_ERRORS } from './default-form-errors'; | |
/** | |
* Handle <mat-form-field> error messages. | |
* | |
* @example | |
* <mat-error matErrorMessage /> | |
* <mat-error | |
* matErrorMessage | |
* [customErrors]="{ | |
* required: 'This could be a custom required error' | |
* }" | |
* /> | |
* | |
* | |
* @usageNotes | |
* Add 'matErrorMessage' attribute selector to <mat-error> within <mat-form-field>. | |
* The customErrors input allows custom errors to be supplied. | |
*/ | |
@Component({ | |
standalone: true, | |
// eslint-disable-next-line @angular-eslint/component-selector | |
selector: 'mat-error[matErrorMessage]', | |
imports: [AsyncPipe], | |
template: '{{ message$ | async }}', | |
changeDetection: ChangeDetectionStrategy.OnPush, | |
}) | |
export class MatErrorMessageComponent implements AfterViewInit, OnDestroy { | |
readonly container = inject(MatFormField); | |
readonly errors = inject(DEFAULT_FORM_ERRORS); | |
private subscription = new Subscription() || undefined; | |
message$ = new BehaviorSubject<string>(''); | |
@Input() customErrors?: ValidationErrors; | |
ngAfterViewInit(): void { | |
const matControl = this.container._control; | |
this.subscription = matControl.stateChanges | |
.pipe(filter(() => matControl.errorState && !matControl.focused)) | |
.subscribe(() => { | |
const controlErrors = matControl.ngControl?.errors; | |
if (controlErrors) { | |
const firstKey = Object.keys(controlErrors)[0]; | |
const getError = this.errors[firstKey]; | |
const text = | |
this.customErrors?.[firstKey] || getError(controlErrors[firstKey]); | |
this.setError(text); | |
} else { | |
this.setError(''); | |
} | |
}); | |
} | |
setError(text: string) { | |
this.message$.next(text); | |
} | |
ngOnDestroy() { | |
if (this.subscription) { | |
this.subscription.unsubscribe(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment