ngx-formcontrol-errors-msgs
Version:
A directive for showing errors in Angular form controls on reactive forms
258 lines (246 loc) • 10.6 kB
JavaScript
import * as i0 from '@angular/core';
import { Input, ChangeDetectionStrategy, Component, InjectionToken, Optional, Inject, Injectable, HostListener, Host, Directive } from '@angular/core';
import { Subscription } from 'rxjs';
import * as i2 from '@angular/forms';
/**
* Readable messages for the built-in valitators
*/
const Messages = {
required: 'This field is required',
min: 'The minimun allowed values is {{min}}',
max: 'The max allowed value is {{max}}',
minlength: 'The minimun allowed length is {{requiredLength}}',
maxlength: 'The max allowed length is {{requiredLength}}',
email: 'Invalid email',
pattern: 'Invalid pattern',
};
class NgxFormcontrolErrorsComponent {
set messages(msgs) {
if (!msgs?.length) {
this.elementRef.nativeElement.innerHTML = '';
return;
}
const msg = msgs[0].message;
this.elementRef.nativeElement.innerHTML = msg;
}
constructor(elementRef) {
this.elementRef = elementRef;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: NgxFormcontrolErrorsComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.2", type: NgxFormcontrolErrorsComponent, isStandalone: true, selector: "ngx-formcontrol-errors", inputs: { messages: "messages" }, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: NgxFormcontrolErrorsComponent, decorators: [{
type: Component,
args: [{
selector: 'ngx-formcontrol-errors',
standalone: true,
template: ``,
changeDetection: ChangeDetectionStrategy.OnPush,
}]
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { messages: [{
type: Input
}] } });
const ERROR_MSG_COMPONENT_FACTORY = new InjectionToken('ERROR_MSG_COMPONENT_FACTORY');
const ERROR_MSG_PARSER = new InjectionToken('ERROR_MSG_PARSER');
/**
* InjectionToken to allow customization of messages by injecting new ones
*/
const FORM_ERROR_MESSAGES_PROVIDER = new InjectionToken('FORM_ERROR_MESSAGES_PROVIDER');
function validationErrors2KeyValue(error
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) {
const errorKeys = Object.keys(error);
return errorKeys.map((keyError) => {
const errorData = error[keyError];
return { key: keyError, value: errorData };
});
}
class ErrorMsgParserService {
constructor(customErrorMessages) {
this.customErrorMessages = customErrorMessages;
this.errorMessages = { ...Messages };
this.errorMessages = {
...this.errorMessages,
...(this.customErrorMessages || {}),
};
}
getMessageByKey(key) {
return this.errorMessages[key];
}
errorMessageParser(errorKey, valueKey, value) {
const message = this.getMessageByKey(errorKey);
if (!message) {
throw new Error(`Error message for ${errorKey} not found`);
}
return message.trim().replace(`{{${valueKey}}}`, (value ?? '').toString());
}
parse(error) {
return validationErrors2KeyValue(error).map(({ key, value }) => {
let valueKey = key;
if (valueKey === 'minlength' || valueKey === 'maxlength') {
valueKey = 'requiredLength';
}
return {
message: this.errorMessageParser(key, valueKey, value[valueKey]),
value,
};
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: ErrorMsgParserService, deps: [{ token: FORM_ERROR_MESSAGES_PROVIDER, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: ErrorMsgParserService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: ErrorMsgParserService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [FORM_ERROR_MESSAGES_PROVIDER]
}] }] });
/**
* Allows ease way to display `ValidationErrors` in a form.
*
* @example
*
* ```typescript
* @Component({
* selector: 'app-form',
* standalone: true,
* imports: [FormcontrolErrorsDirective, ReactiveFormsModule],
* template: `
* <form [formGroup]="form">
* <div class="form-row">
* <label for="name">Name</label>
* <input id="name" type="text" formControlName="name" ngxFormcontrolErrors>
* </div>
* <div class="form-row">
* <label for="email">Email</label>
* <input id="email" type="email" formControlName="email" ngxFormcontrolErrors>
* </div>
* </form>
* `
* })
* export class AppComponent {
*
* form = this.formBuilder.group({
* name: ['', [Validators.required, Validators.maxLength(10)]],
* email: ['', [Validators.required, Validators.email]],
* });
*
* }
* ```
*
*/
class FormcontrolErrorsDirective {
/**
* @internal
*/
onBlur() {
this.control.markAsTouched();
this.validataStatus(this.control.status);
}
constructor(viewContainerRef, errorMsgParser, formGroup, formControlName, formControl, customErrorMsgParser, errorMessageComponentFactory) {
this.viewContainerRef = viewContainerRef;
this.errorMsgParser = errorMsgParser;
this.formGroup = formGroup;
this.formControlName = formControlName;
this.formControl = formControl;
this.customErrorMsgParser = customErrorMsgParser;
this.errorMessageComponentFactory = errorMessageComponentFactory;
this.errorInfoComponent = null;
this.sub$ = new Subscription();
}
/**
* @internal
*/
ngOnInit() {
this.control = this.formControlName?.control || this.formControl;
if (!this.control) {
throw new Error('No control found, `ngxFormControlErrors` must be used with `formControlName` or `formControl`');
}
this.errorParser = this.customErrorMsgParser || this.errorMsgParser;
if (this.errorMessageComponentFactory) {
this.errorInfoComponent =
this.errorMessageComponentFactory.createComponent(this.viewContainerRef);
}
else {
this.errorInfoComponent = this.viewContainerRef.createComponent(NgxFormcontrolErrorsComponent);
}
this.sub$.add(this.formGroup.ngSubmit.subscribe(() => {
if (!this.control.touched) {
this.control.markAsTouched();
this.validataStatus(this.control?.status);
}
}));
this.sub$.add(this.control.statusChanges?.subscribe((status) => {
this.validataStatus(status);
}));
}
/**
* @internal
*/
ngOnDestroy() {
this.sub$.unsubscribe();
}
/**
* @internal
*/
validataStatus(status) {
if (!this.errorInfoComponent) {
throw new Error('No error info component found');
}
if (!this.errorParser) {
throw new Error('No error parser found');
}
if ('INVALID' === status && this.control?.touched) {
this.errorInfoComponent.instance.messages = this.errorParser.parse(this.control.errors);
}
else if ('DISABLED' === status ||
status === 'VALID' ||
this.control?.untouched) {
this.errorInfoComponent.instance.messages = null;
this.errorInfoComponent.changeDetectorRef.detectChanges();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: FormcontrolErrorsDirective, deps: [{ token: i0.ViewContainerRef }, { token: ErrorMsgParserService }, { token: i2.FormGroupDirective }, { token: i2.FormControlName, host: true, optional: true }, { token: i2.FormControl, host: true, optional: true }, { token: ERROR_MSG_PARSER, optional: true }, { token: ERROR_MSG_COMPONENT_FACTORY, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.2", type: FormcontrolErrorsDirective, isStandalone: true, selector: "[ngxFormcontrolErrors]", host: { listeners: { "blur": "onBlur()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: FormcontrolErrorsDirective, decorators: [{
type: Directive,
args: [{
selector: '[ngxFormcontrolErrors]',
standalone: true,
}]
}], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: ErrorMsgParserService }, { type: i2.FormGroupDirective }, { type: i2.FormControlName, decorators: [{
type: Optional
}, {
type: Host
}] }, { type: i2.FormControl, decorators: [{
type: Optional
}, {
type: Host
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [ERROR_MSG_PARSER]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [ERROR_MSG_COMPONENT_FACTORY]
}] }], propDecorators: { onBlur: [{
type: HostListener,
args: ['blur']
}] } });
/*
* Public API Surface of ngx-formcontrol-errors
*/
/**
* Generated bundle index. Do not edit.
*/
export { ERROR_MSG_COMPONENT_FACTORY, ERROR_MSG_PARSER, ErrorMsgParserService, FORM_ERROR_MESSAGES_PROVIDER, FormcontrolErrorsDirective, Messages, validationErrors2KeyValue };
//# sourceMappingURL=ngx-formcontrol-errors-msgs.mjs.map