UNPKG

ngx-form-validator-super

Version:

A super flexible and time saving Validation logic handeling directive for Angular Reactive forms.

529 lines (518 loc) 20.7 kB
import { Component, ɵɵdefineInjectable, Injectable, ɵɵinject, Directive, ElementRef, HostListener, Optional, Input, NgModule } from '@angular/core'; import { FormControl, FormArray, FormGroup, ControlContainer, NgControl, NgModel } from '@angular/forms'; class NgxFormValidatorComponent { constructor() { } ngOnInit() { } } NgxFormValidatorComponent.decorators = [ { type: Component, args: [{ selector: 'lib-ngx-form-validator', template: ` <p> ngx-form-validator works! </p> ` },] } ]; NgxFormValidatorComponent.ctorParameters = () => []; class PanelLogic { constructor() { this.IsConsoleShow = false; this.pos1 = 0; this.pos2 = 0; this.pos3 = 0; this.pos4 = 0; } updateControlStatus(formControl, allControls) { this.Control = formControl; this.AllControls = allControls; let div = document.getElementById('__XConsl'); if (!this.IsConsoleShow) { if (div) { div.style.display = "none"; } return; } if (!div) { div = document.createElement('div'); //let div = document.createElement('div'); div.style.position = "fixed"; div.id = "__XConsl"; div.style.top = "20px"; div.style.zIndex = "999"; div.style.minHeight = "350px"; div.style.width = "350px"; div.style.overflow = "auto"; div.style.maxHeight = "90vh"; div.style.right = "30px"; div.style.padding = "0px"; div.style.fontSize = "13px"; div.style.border = "1px solid #dfdfdf"; div.style.backgroundColor = "#fff"; div.style.boxShadow = "0px 2px 3px #00000022"; document.getElementsByTagName('body')[0].append(div); } div.style.display = "block"; let content = ""; setTimeout(() => { // this.dragElement(div) let controlCopy = this.Control.form.controls; //let AllControls = this.ValidatorLogic.GetAllControls(controlCopy); content += "<div id=\"_ngx-super-ff\" style='background-color:#707070;font-family:arial ;text-align:center;color:#fff;padding:4px;'>Form Valid : " + this.Control.form.valid + " </div>"; content += "<table style=\"width:100%;margin:4px;\" class=\"_ng-super-panel\">"; content += "<tr>"; content += "<th>Control</th><th>Validation</th><th>Value</th>"; content += "</tr>"; this.AllControls.forEach(e => { content += `<tr> <td style="text-align:center;font-falimy:arial; border:1px solid #efefef;padding:2px` + (e.errors ? `;border-left:4px solid #DA4667;color:#000;"` : `;border-left:4px solid #5EFF00;color:#555;`) + `"> ` + e.name + ` </td> <td> ` + JSON.stringify(e.errors) + `</td> <td style="min-width:100px;"> ` + e.value + ` </span> </tr> `; }); content += "</table>"; div.innerHTML = content; }, 200); } //dragElement(document.getElementById("mydiv")); dragElement(elmnt) { if (document.getElementById("_ngx-super-ff")) { // if present, the header is where you move the DIV from: document.getElementById("_ngx-super-ff").onmousedown = this.dragMouseDown; } else { // otherwise, move the DIV from anywhere inside the DIV: elmnt.onmousedown = this.dragMouseDown; } } dragMouseDown(e) { e = e || window.event; e.preventDefault(); // get the mouse cursor position at startup: this.pos3 = e.clientX; this.pos4 = e.clientY; document.onmouseup = this.closeDragElement; // call a function whenever the cursor moves: document.onmousemove = this.elementDrag; } elementDrag(e) { e = e || window.event; e.preventDefault(); // calculate the new cursor position: this.pos1 = this.pos3 - e.clientX; this.pos2 = this.pos4 - e.clientY; this.pos3 = e.clientX; this.pos4 = e.clientY; // set the element's new position: e.style.top = (e.offsetTop - this.pos2) + "px"; e.style.left = (e.offsetLeft - this.pos1) + "px"; } closeDragElement() { // stop moving when mouse button is released: document.onmouseup = null; document.onmousemove = null; } } PanelLogic.ɵprov = ɵɵdefineInjectable({ factory: function PanelLogic_Factory() { return new PanelLogic(); }, token: PanelLogic, providedIn: "root" }); PanelLogic.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; PanelLogic.ctorParameters = () => []; class ValidatorLogic { constructor(panelLogic) { this.panelLogic = panelLogic; this.ValidationLabels = {}; } GetAllControls(controls) { let extractedControls = []; for (let ctrl in controls) { if (controls[ctrl] instanceof FormControl) { controls[ctrl].name = ctrl; extractedControls.push(controls[ctrl]); // Setting control status to valid for elements thata are nto visible on UI if (!controls[ctrl].nativeElement) { controls[ctrl].errors = null; controls[ctrl].status = 'VALID'; } else if ((!document.body.contains(controls[ctrl].nativeElement))) { controls[ctrl].setValue(null); controls[ctrl].errors = null; controls[ctrl].status = 'VALID'; } else { controls[ctrl].updateValueAndValidity({ emitEvent: false }); } } if (controls[ctrl] instanceof FormArray) { extractedControls = [...extractedControls, ...this.GetAllControls(controls[ctrl].controls)]; } if (controls[ctrl] instanceof FormGroup) { extractedControls = [...extractedControls, ...this.GetAllControls(controls[ctrl].controls)]; } } return extractedControls; } ValidateControls(changedControl) { try { let allControls = this.GetAllControls(this.formControl.form.controls); let controls = []; let selectedControlIndex = -1; let hasError = false; if (changedControl) { selectedControlIndex = allControls.findIndex(x => (x.nativeElement && x.nativeElement.isSameNode(changedControl))); controls = allControls.map((x, index) => { if (index != selectedControlIndex) { return index; } else return -1; }).filter((x) => x != -1); } this.errorControl = null; allControls.forEach((formControl, index) => { if (formControl.nativeElement) if ((!controls.includes(index) && formControl.nativeElement.type == "checkbox") || (selectedControlIndex > -1 && (!controls.includes(index) || (index == selectedControlIndex))) || ((selectedControlIndex == -1) && formControl.nativeElement.type != "checkbox")) { this.AddRemoveErrorMsg(false, "", formControl.nativeElement); // Show validation msg only when forms submits not when control value changes if (!changedControl || index == selectedControlIndex) { for (let errorName in formControl.errors) { let erroObj = {}; erroObj[errorName] = formControl.errors[errorName]; hasError = true; // if(!changedControl) this.setErrorControl(formControl.nativeElement); this.AddRemoveErrorMsg(true, erroObj, formControl.nativeElement); } } controls.push(index); } }); if (!hasError) { this.formControl['form'].status = 'VALID'; } this.panelLogic.updateControlStatus(this.formControl, allControls); if (this.errorControl && !changedControl) { // this.toatser.error("Please fill the required details.", "Error !") this.scrollTo(this.errorControl.ele); } return hasError; } catch (ex) { console.error(ex); } } setErrorControl(element) { let yAxis = element.getBoundingClientRect().y; if (!this.errorControl) { this.errorControl = { ele: element, y: yAxis }; return; } if (this.errorControl.y > yAxis) { this.errorControl = { ele: element, y: yAxis }; } } scrollTo(element) { if (element) { element.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" }); let t = null; let func = () => { t = setTimeout(() => { element.focus(); window.onscroll = null; }, 100); }; func(); window.onscroll = () => { if (t) { clearTimeout(t); t = null; } func(); }; } } GetValidationType(ele) { if (!ele.attributes["validationHint"]) { return 1; } let validationType = ele.attributes["validationHint"].value; if (validationType = "borderOnly") { return 2; } return 1; } GetValidationContainer(ele) { if (!ele.attributes["validationContainerId"]) { return null; } return document.getElementById(ele.attributes["validationContainerId"].value) || null; } AddRemoveErrorMsg(isAdd, error, ele) { if (!ele || !ele.parentElement) { return; } let validationContainer = this.GetValidationContainer(ele); let validationType = this.GetValidationType(ele); let childs = []; let errorName = error ? Object.keys(error)[0] : null; let errorObj = error ? error[errorName] : null; ele.classList.remove('_BrdrError'); if (validationContainer) { if (validationContainer.childNodes.length > 0) { childs = validationContainer.childNodes; } } else { childs = ele.parentElement.childNodes; } if (validationType == 2) { ele.classList.remove('_BrdrError'); if (validationContainer) { validationContainer.classList.remove('_BrdrError'); } } for (let i = 0; i < childs.length; i++) { if (childs[i].classList && childs[i].classList.contains('_ErX')) { childs[i].remove(); } } if (isAdd) { let div = document.createElement('div'); if (validationType == 2) { if (validationContainer) { validationContainer.classList.add('_BrdrError'); } else { ele.classList.add('_BrdrError'); } return; } ele.classList.add('_BrdrError'); div.classList.add('_ErX'); this.GetErrorMsg(errorName, errorLabel => { if (errorLabel && (errorObj.hasOwnProperty('requiredLength') || errorObj.hasOwnProperty('max'))) { errorLabel = errorLabel.replace('_', errorObj.requiredLength || errorObj.max); } div.innerHTML = ' <small class="ngx-validation-label " >' + errorLabel + '</small>'; // Adding validation msg to given container element if (validationContainer) { //If container has childs if (validationContainer.childNodes.lenght > 0) { validationContainer.children[validationContainer.children.length - 1].insertAdjacentElement('beforeend', div); } else { // if container has no child validationContainer.appendChild(div); } } else { // adding validation on from control it self ele.parentElement.insertAdjacentElement("beforeend", div); } }); } } GetErrorMsg(errorCode, cb) { let eCode = { required: "This field is required.", email: "Invalid email.", number: "Invalid number", max: "Maxlength exceeds", minlength: "Minimum length of this field must be _ .", invalidOfficerTitle: "Select valid Officer Title.", requiredExpiryDate: "Please enter card's expiry date.", inavlidExpiryDate: "Past date is not allowed", phoneLength: "Phone number must be _ digits long.", zipLength: "Zip must be _ digits long.", }; cb(this.ValidationLabels[errorCode]); } TogglePanel() { this.panelLogic.IsConsoleShow = !this.panelLogic.IsConsoleShow; this.panelLogic.updateControlStatus(this.formControl, this.GetAllControls(this.formControl.form.controls)); } } ValidatorLogic.ɵprov = ɵɵdefineInjectable({ factory: function ValidatorLogic_Factory() { return new ValidatorLogic(ɵɵinject(PanelLogic)); }, token: ValidatorLogic, providedIn: "root" }); ValidatorLogic.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; ValidatorLogic.ctorParameters = () => [ { type: PanelLogic } ]; class NGXFormValidator { constructor(controlContainer, ValidatorLogic, ele) { this.controlContainer = controlContainer; this.ValidatorLogic = ValidatorLogic; this.ele = ele; this.btnClickHandler = (event) => { event.preventDefault(); this.CallValidation(event.target); }; this.SetMutationOserver(); } ngOnInit() { } SetMutationOserver() { if (!this.ele) { return; } let observer = new MutationObserver((mutations) => { let buttons = this.GetSubmitButtons(); if (buttons && buttons.length > 0) { buttons.forEach(button => { this.OnSubmitBtnClick(button); }); } }); observer.observe(this.ele.nativeElement, { childList: true, subtree: true, attributes: true }); } GetSubmitButtons() { if (!this.ele) { return; } let submitButtons = this.ele.nativeElement.querySelectorAll("button[type=submit]"); return submitButtons; } OnSubmitBtnClick(btnRef) { btnRef.removeEventListener('click', this.btnClickHandler); btnRef.addEventListener('click', this.btnClickHandler); } CallValidation(target) { this.ValidatorLogic.formControl = this.controlContainer; if (!this.ValidatorLogic.ValidateControls(null)) { target.removeEventListener('click', this.btnClickHandler); target.click(); } } change(event) { this.ValidatorLogic.formControl = this.controlContainer; if (event.srcElement.attributes.formcontrolname) { this.ValidatorLogic.ValidateControls(event.srcElement); } } submit(e) { //e.currentTarget.stopPropagation(); //this.ValidatorLogic.formControl = this.controlContainer // this.ValidatorLogic.ValidateControls(null); // e.target.onSubmit=null; return false; } openPanel() { this.ValidatorLogic.formControl = this.controlContainer; this.ValidatorLogic.TogglePanel(); } } NGXFormValidator.decorators = [ { type: Directive, args: [{ selector: '[ngxValidator]' },] } ]; NGXFormValidator.ctorParameters = () => [ { type: ControlContainer }, { type: ValidatorLogic }, { type: ElementRef } ]; NGXFormValidator.propDecorators = { change: [{ type: HostListener, args: ["change", ["$event"],] }], submit: [{ type: HostListener, args: ["submit", ["$event"],] }], openPanel: [{ type: HostListener, args: ['document:keydown.shift.f8', ['$event'],] }] }; class NativeElementInjectorDirective { constructor(el, control, model) { this.el = el; this.control = control; this.model = model; this.appendNativeElement(); } onChange(event) { this.appendNativeElement(); } ngAfterViewInit() { this.appendNativeElement(); } appendNativeElement() { if (!!this.model) this.model.control.nativeElement = this.el.nativeElement; else if (this.control.control) this.control.control.nativeElement = this.el.nativeElement; } } NativeElementInjectorDirective.decorators = [ { type: Directive, args: [{ selector: '[ngModel], [formControl], [formControlName]', },] } ]; NativeElementInjectorDirective.ctorParameters = () => [ { type: ElementRef }, { type: NgControl }, { type: NgModel, decorators: [{ type: Optional }] } ]; NativeElementInjectorDirective.propDecorators = { validationContainerId: [{ type: Input, args: ['validationContainerId',] }], onChange: [{ type: HostListener, args: ['change', ['$event'],] }] }; class NgxValidatorLabelService { constructor(ValidatorLogic) { this.ValidatorLogic = ValidatorLogic; } setValidationMsg(labels) { this.ValidatorLogic.ValidationLabels = labels; } appendValidationMsg(labels) { this.ValidatorLogic.ValidationLabels = Object.assign({}, labels); } clearValidationMsg() { this.ValidatorLogic.ValidationLabels = {}; } } NgxValidatorLabelService.ɵprov = ɵɵdefineInjectable({ factory: function NgxValidatorLabelService_Factory() { return new NgxValidatorLabelService(ɵɵinject(ValidatorLogic)); }, token: NgxValidatorLabelService, providedIn: "root" }); NgxValidatorLabelService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; NgxValidatorLabelService.ctorParameters = () => [ { type: ValidatorLogic } ]; class TestComponent { constructor() { } ngOnInit() { } } TestComponent.decorators = [ { type: Component, args: [{ selector: 'lib-test', template: "<p>test works!</p>\n", styles: [""] },] } ]; TestComponent.ctorParameters = () => []; class NgxFormValidatorModule { static forRoot() { return { ngModule: NgxFormValidatorModule, providers: [NgxValidatorLabelService] }; } } NgxFormValidatorModule.decorators = [ { type: NgModule, args: [{ declarations: [NgxFormValidatorComponent, NGXFormValidator, NativeElementInjectorDirective, TestComponent], imports: [], exports: [NgxFormValidatorComponent, NGXFormValidator, NativeElementInjectorDirective ], providers: [ ValidatorLogic, NgxValidatorLabelService ] },] } ]; /* * Public API Surface of ngx-form-validator */ /** * Generated bundle index. Do not edit. */ export { NGXFormValidator, NativeElementInjectorDirective, NgxFormValidatorComponent, NgxFormValidatorModule, NgxValidatorLabelService, ValidatorLogic as ɵa, PanelLogic as ɵb, TestComponent as ɵc }; //# sourceMappingURL=ngx-form-validator-super.js.map