UNPKG

ngx-formcontrol-errors-msgs

Version:

A directive for showing errors in Angular form controls on reactive forms

258 lines (246 loc) 10.6 kB
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