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
JavaScript
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