UNPKG

ngx-error-message

Version:

A package to display error messages in angular forms

293 lines (282 loc) 12.5 kB
import * as i0 from '@angular/core'; import { InjectionToken, inject, Injectable, Pipe, ElementRef, Renderer2, Input, Component, ViewContainerRef, Directive, NgModule } from '@angular/core'; import { NgControl } from '@angular/forms'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; import { Subject, distinctUntilChanged } from 'rxjs'; import { CommonModule } from '@angular/common'; const octetPattern = '(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})'; const countryCode = '\\+?[-.\\s]?\\d{1,2}[-.\\s]?'; const areaCode = '\\(?\\d{3}\\)?'; const phoneNumber = '\\d{3}[-.\\s]?\\d{4}'; const protocol = '(https?:\\/\\/)?'; const domain = '[\\w\\d-]+(\\.[\\w\\d-]+)+'; const path = '(\\/[-\\w\\d.]*)*\\/?'; const query = '(\\?[\\w\\d=&]*)?'; const fragment = '(#[\\w\\d-]*)?'; const regEx = { phoneNumber: new RegExp(`^(${countryCode})?${areaCode}[-.\\s]?${phoneNumber}$`), websiteUrl: new RegExp(`^${protocol}${domain}${path}${query}${fragment}$`), numeric: /^\d+$/, smallLetters: /^[a-z]+$/, capitalLetters: /^[A-Z]+$/, alphabet: /^[a-zA-Z\s\u00C0-\u017F]+$/, alphaNumeric: /^[a-zA-Z0-9\s\u00C0-\u017F]+$/, ip: new RegExp(`^(${octetPattern})(\\.(${octetPattern})){3}$`), }; const requiredRegex = /^((?!actual).)*$/; const ERROR_MESSAGE_CONFIG = new InjectionToken('ERROR_MESSAGE_CONFIG'); class NgxErrorMessageService { config = inject(ERROR_MESSAGE_CONFIG); translate = inject(TranslateService, { optional: true }); getErrorMessage(controlErrors, patternKey, fieldName) { const lastError = Object.entries(controlErrors).pop(); if (!lastError) { return ''; } const [errorKey, errorValue] = lastError; if (typeof errorValue === 'boolean') { return this.getMessage(errorKey, fieldName); } if (errorKey === 'pattern') { const patternErrorKey = this.patternMatchExpression(errorValue, patternKey); return this.getMessage(patternErrorKey, fieldName); } const requiredValue = this.getValueByRegexFromObject(errorValue, requiredRegex); return this.getMessage(errorKey, fieldName, requiredValue); } patternMatchExpression(value, patternKey) { const pattern = value['requiredPattern']; const regExpDefault = Object.entries(regEx).find(([, val]) => val.toString() === pattern); return `${this.config.patternsPrefix}.${regExpDefault ? regExpDefault[0] : patternKey}`; } getValueByRegexFromObject(obj, regex) { const [, findValue] = Object.entries(obj).find(([key]) => regex.test(key)) ?? []; return findValue; } interpolateMessage(message, params) { return message.replace(/\{\{(\w+)\}\}/g, (_, key) => params[key] ?? ''); } getNestedMessage(obj, path) { return path .split('.') .reduce((acc, key) => acc && acc[key], obj); } getMessage(key, fieldName, param) { const options = { ...(fieldName && { fieldName }), ...(param && { param }), }; if (Object.keys(this.config.errorMessages).length > 0) { const messageTemplate = this.getNestedMessage(this.config.errorMessages, key) ?? ''; return this.interpolateMessage(messageTemplate, options); } return param || fieldName ? this.translate?.instant(`${this.config.validationsPrefix}.${key}`, options) : this.translate?.instant(`${this.config.validationsPrefix}.${key}`); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageService, decorators: [{ type: Injectable }] }); class NgxErrorMessagePipe { errorMessageService = inject(NgxErrorMessageService); cachedData; cachedError = ''; cachedLang = ''; transform(value, lang, patternKey, fieldName) { if (!value) { return ''; } if (lang !== this.cachedLang) { this.cachedLang = lang ?? ''; this.cachedError = ''; } const [lastErrorKey] = Object.keys(value).slice(-1); if (lastErrorKey !== this.cachedError) { this.cachedError = lastErrorKey; this.cachedData = this.errorMessageService.getErrorMessage(value, patternKey, fieldName); } return this.cachedData ?? ''; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessagePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessagePipe, isStandalone: true, name: "ngxErrorMessage" }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessagePipe, decorators: [{ type: Pipe, args: [{ name: 'ngxErrorMessage', }] }] }); class NgxErrorMessageComponent { classNames; fieldName; ngControl; when; patternKey; lang; translate = inject(TranslateService); elementRef = inject(ElementRef); renderer = inject(Renderer2); destroy$ = new Subject(); previousErrorState = false; get hasError() { const invalid = Array.isArray(this.when) ? this.when.every((condition) => this.ngControl[condition]) : this.ngControl[this.when]; if (this.previousErrorState !== invalid) { this.previousErrorState = !!invalid; this.updateErrorContainer(!!invalid); } return !!invalid; } ngOnInit() { this.translate.onLangChange .pipe(distinctUntilChanged()) .subscribe(({ lang }) => (this.lang = lang)); } updateErrorContainer(invalid) { const inputElement = this.elementRef.nativeElement.previousElementSibling; if (!inputElement) { return; } const errorClass = this.classNames.control; invalid ? this.renderer.addClass(inputElement, errorClass) : this.renderer.removeClass(inputElement, errorClass); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.8", type: NgxErrorMessageComponent, isStandalone: true, selector: "ngx-error-message", inputs: { classNames: "classNames", fieldName: "fieldName", ngControl: "ngControl", when: "when", patternKey: "patternKey" }, ngImport: i0, template: ` @if (hasError) { <small [class]="classNames.message">{{ ngControl.errors | ngxErrorMessage: lang : patternKey : fieldName }}</small> } `, isInline: true, dependencies: [{ kind: "pipe", type: NgxErrorMessagePipe, name: "ngxErrorMessage" }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-error-message', template: ` @if (hasError) { <small [class]="classNames.message">{{ ngControl.errors | ngxErrorMessage: lang : patternKey : fieldName }}</small> } `, imports: [NgxErrorMessagePipe], }] }], propDecorators: { classNames: [{ type: Input }], fieldName: [{ type: Input }], ngControl: [{ type: Input }], when: [{ type: Input }], patternKey: [{ type: Input }] } }); class NgxErrorMessageDirective { set ngxErrorMessage(value) { this.fieldName = value; if (!this.componentRef) { return; } this.componentRef.instance.fieldName = this.fieldName; } classNames = { control: 'error-container', message: 'error-message', }; patternKey; when = ['invalid', 'touched']; fieldName = ''; ngControl = inject(NgControl); container = inject(ViewContainerRef); componentRef; ngOnInit() { const hostViewContainerRef = this.container; if (!this.componentRef) { hostViewContainerRef.clear(); this.componentRef = hostViewContainerRef.createComponent(NgxErrorMessageComponent); } const instance = this.componentRef.instance; instance.classNames = this.classNames; instance.ngControl = this.ngControl; instance.patternKey = this.patternKey; instance.when = this.when; instance.fieldName = this.fieldName; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.8", type: NgxErrorMessageDirective, isStandalone: true, selector: "[ngxErrorMessage]", inputs: { ngxErrorMessage: "ngxErrorMessage", classNames: "classNames", patternKey: "patternKey", when: "when" }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageDirective, decorators: [{ type: Directive, args: [{ selector: '[ngxErrorMessage]', }] }], propDecorators: { ngxErrorMessage: [{ type: Input }], classNames: [{ type: Input }], patternKey: [{ type: Input }], when: [{ type: Input }] } }); class NgxErrorMessageModule { static forRoot(config) { return NgxErrorMessageModule.forRootOrChild(config); } static forChild(config) { return NgxErrorMessageModule.forRootOrChild(config); } static forRootOrChild(config) { return { ngModule: NgxErrorMessageModule, providers: [ { provide: ERROR_MESSAGE_CONFIG, useValue: { validationsPrefix: config?.validationsPrefix ?? 'validations', patternsPrefix: config?.patternsPrefix ?? 'pattern', errorMessages: config?.errorMessages ?? {}, }, }, NgxErrorMessageService, ], }; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageModule, imports: [CommonModule, TranslateModule, NgxErrorMessageComponent, NgxErrorMessageDirective, NgxErrorMessagePipe], exports: [NgxErrorMessageDirective] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageModule, imports: [CommonModule, TranslateModule] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: NgxErrorMessageModule, decorators: [{ type: NgModule, args: [{ imports: [ CommonModule, TranslateModule, NgxErrorMessageComponent, NgxErrorMessageDirective, NgxErrorMessagePipe, ], exports: [NgxErrorMessageDirective], }] }] }); /* * Public API Surface of ngx-error-message */ /** * Generated bundle index. Do not edit. */ export { NgxErrorMessageDirective, NgxErrorMessageModule, NgxErrorMessageService, regEx }; //# sourceMappingURL=ngx-error-message.mjs.map