UNPKG

lc-forms

Version:

Is a library for simplified object-based creation and validation of forms in Angular/Angular Universal. The library is inspired by [angular.io dynamic forms](https://angular.io/docs/ts/latest/cookbook/dynamic-form.html) and [Filip Lauc's](https://github.c

432 lines (419 loc) 15.6 kB
import { CommonModule } from '@angular/common'; import { Component, EventEmitter, HostBinding, Injectable, Input, NgModule, Output } from '@angular/core'; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; class LCCustomValidators { /** * @param {?} key * @return {?} */ static match(key) { return (control) => { if (control.value && control.root.controls) { return control.root.controls[key].value !== control.value ? { 'match': { 'currentValue': control.value, 'requiredValue': control.root.controls[key].value, 'mustMatchField': key } } : null; } else { return null; } }; } } class LCFormService { /** * @param {?} elements * @return {?} */ create(elements) { const /** @type {?} */ temp = {}, /** @type {?} */ toReturn = {}, /** @type {?} */ matches = []; elements.forEach(e => { const /** @type {?} */ val = e.value || ''; let /** @type {?} */ validators = null; if (e.validation) { if (Array.isArray(e.validation)) { validators = []; e.validation.forEach(i => validators.push(setValidator(i, e))); } else { validators = setValidator(e.validation); } } temp[e.key] = new FormControl(val, validators); }); toReturn['fbGroup'] = new FormGroup(temp); // Add matches for watching if required if (matches.length) { toReturn['matches'] = matches; } return toReturn; /** * @param {?} item * @param {?=} original * @return {?} */ function setValidator(item, original) { switch (item.type) { case 'required': return Validators.required; case 'minLength': return Validators.minLength(item.value); case 'maxLength': return Validators.maxLength(item.value); case 'pattern': return Validators.pattern(item.value); case 'match': matches.push({ toMatch: item.value, model: original.key }); return LCCustomValidators.match(item.value); } } } } LCFormService.decorators = [ { type: Injectable }, ]; /** * @nocollapse */ LCFormService.ctorParameters = () => []; class LCFormComponent { /** * @param {?} _controlGroup */ constructor(_controlGroup) { this._controlGroup = _controlGroup; // Outputs this.submitted = new EventEmitter(); this.changed = new EventEmitter(); } /** * @param {?} value * @return {?} */ set lcFormData(value) { this._data = value; this._data.settings = this._setSettings(value.settings); this.sortElements(); const /** @type {?} */ cg = this._controlGroup.create(this._data.elements); this._form = cg.fbGroup; this._matches = cg.matches; this.comp = { data: this._data, form: this._form, settings: { singleErrorMessage: this._data.settings.singleErrorMessage, errorOnDirty: this._data.settings.errorOnDirty, showValidation: this._data.settings.showValidation, extraValidation: this._data.settings.submitButtonExtraValidation || true } }; } /** * @return {?} */ submit() { this.submitted.emit(this._form.value); } /** * @param {?} event * @return {?} */ onElementValueChange(event) { if (this._matches) { // console.log('this._matches: ', this._matches); const /** @type {?} */ key = Object.keys(event)[0], /** @type {?} */ // See if we should check for matches mat = this._matches[0].find(a => a.toMatch === key); // Update the cg if we found a matcher if (mat) { this._form.controls[mat.model].updateValueAndValidity(); } } this.changed.emit(event); } /** * @return {?} */ sortElements() { this._data.elements.sort((a, b) => a.order - b.order); } /** * @param {?} settings * @return {?} */ _setSettings(settings) { const /** @type {?} */ defaultSettings = { submitButton: true, submitButtonText: 'Submit', submitButtonExtraValidation: null, noteText: null, noteLabel: null, showValidation: true, singleErrorMessage: true, errorOnDirty: true }; // Add received settings if (settings) { for (const /** @type {?} */ p in defaultSettings) { if (settings.hasOwnProperty(p)) { defaultSettings[p] = settings[p]; } else { defaultSettings[p] = defaultSettings[p]; } } } return defaultSettings; } } LCFormComponent.decorators = [ { type: Component, args: [{ template: ` <form [formGroup]="comp.form" [ngClass]="comp.data.classes?.form"> <lc-element *ngFor="let e of comp.data.elements" [info]="{element: e, form: comp.form, settings: comp.settings, classes: comp.data.classes}" (valueChange)="onElementValueChange($event)"></lc-element> <div class="row"> <div *ngIf="comp.data.settings.submitButton" [ngClass]="comp.data.classes?.submit"> <button type="submit" [disabled]="!comp.form.valid && comp.settings.extraValidation" [ngClass]="comp.data.classes?.submitButton">{{comp.data.settings.submitButtonText}}</button> </div> <div *ngIf="comp.data.settings.noteText" [ngClass]="comp.data.classes.note"> <span *ngIf="comp.data.settings.noteLabel" [ngClass]="comp.data.classes.noteLabel">{{comp.data.settings.noteLabel}}</span>&nbsp; {{comp.data.settings.noteText}} </div> </div> </form> `, // tslint:disable-next-line:component-selector selector: 'lc-form' },] }, ]; /** * @nocollapse */ LCFormComponent.ctorParameters = () => [ { type: LCFormService, }, ]; LCFormComponent.propDecorators = { 'lcFormData': [{ type: Input },], 'submitted': [{ type: Output },], 'changed': [{ type: Output },], }; class LCElementComponent { constructor() { this.valueChange = new EventEmitter(); this.checkboxIsRequired = false; } /** * @return {?} */ get toSet() { return this.element && this.element.classes && this.element.classes.wrapper ? this.element.classes.wrapper : ''; } /** * @param {?} value * @return {?} */ set info(value) { this.element = value.element; this.form = value.form; this.settings = value.settings; this.classes = value.classes; if (this.element.type === 'checkbox') { this.element.value = !this.element.value ? [] : this.element.value; this.checkboxIsRequired = this.element.validation && this.element.validation[0].type === 'required'; } if (this.classes.errors) { if (!this.element.classes.error) { this.element.classes.error = this.classes.errors; } else { this.element.classes.error = this.element.classes.error.concat(this.classes.errors); } } } /** * @return {?} */ get showErrorMsg() { return this.settings.errorOnDirty ? !this.form.controls[this.element.key].valid && !this.form.controls[this.element.key].dirty : !this.form.controls[this.element.key].valid; } /** * @return {?} */ errors() { if (this.element.validation && !this.form.controls[this.element.key].valid) { const /** @type {?} */ temp = [], /** @type {?} */ errors = this.form.controls[this.element.key].errors, /** @type {?} */ errorKeys = Object.keys(errors); if (this.settings.singleErrorMessage) { temp.push(this._setError(errorKeys[errorKeys.length - 1], errors)); } else { errorKeys.forEach(a => temp.push(this._setError(a, errors))); } return temp; } } /** * @param {?} option * @return {?} */ setRadio(option) { this.form.controls[this.element.key].setValue(option.value); this.onValueChange(option.value); } /** * @param {?} option * @return {?} */ setCheckbox(option) { const /** @type {?} */ index = this.element.value.indexOf(option.value); if (index !== -1) { this.element.value.splice(index, 1); } else { this.element.value.push(option.value); } this.form.controls[this.element.key].setValue(this.element.value); this.onValueChange(this.element.value); } /** * @return {?} */ chackboxValueChange() { if (this.checkboxIsRequired) { if (this.element.value.length === 1) { this.element.options.find(a => a.value === this.element.value[0]).disabled = true; } else { this.element.options.forEach(a => a.disabled = false); } } } /** * @param {?} event * @return {?} */ onValueChange(event) { if (this.element.emitChanges !== false) { this.valueChange.emit({ [this.element.key]: event }); } } /** * @param {?} option * @return {?} */ isSelectActive(option) { return this.element.value.find(a => a === option.value) ? true : false; } /** * @param {?} item * @param {?} errors * @return {?} */ _setError(item, errors) { let /** @type {?} */ errorMsg = this.element.validation.find(a => a.type.toLowerCase() === item).message; const /** @type {?} */ tag = this.element.label || this.element.key; if (!errorMsg) { switch (item) { // Set error messages case 'required': errorMsg = `${tag} is required.`; break; case 'minlength': errorMsg = `${tag} has to be at least ${errors[item].requiredLength} characters long.`; break; case 'maxlength': errorMsg = `${tag} can't be longer then ${errors[item].requiredLength} characters.`; break; case 'pattern': errorMsg = `${tag} must match this pattern: ${errors[item].requiredPattern}.`; break; case 'match': errorMsg = `${tag} must match the ${errors[item].mustMatchField} field.`; break; } } return errorMsg; } } LCElementComponent.decorators = [ { type: Component, args: [{ // tslint:disable-next-line:component-selector selector: 'lc-element', template: ` <div [formGroup]="form" [ngClass]="element.classes?.group"> <label *ngIf="element.label" [ngClass]="element.classes?.label" [attr.for]="element.key"> {{element.label}} </label> <div [ngSwitch]="element.type"> <select *ngSwitchCase="'dropdown'" [formControlName]="element.key" (ngModelChange)="onValueChange($event)" [ngClass]="element.classes?.element" [id]="element.key"> <option *ngFor="let o of element.options" [value]="o.value">{{o.name ? o.name : o.value}}</option> </select> <div *ngSwitchCase="'checkbox'" [ngClass]="element.classes?.element"> <div class="checkbox" *ngFor="let o of element.options"> <input [type]="element.type" [formControlName]="element.key" [name]="element.key" [value]="o.value" [checked]="isSelectActive(o)" (change)="chackboxValueChange()" (click)="setCheckbox(o)"> <span>{{o.name ? o.name : o.value}}</span> </div> </div> <textarea *ngSwitchCase="'textarea'" [formControlName]="element.key" (ngModelChange)="onValueChange($event)" [id]="element.key" [attr.placeholder]="element.placeholder" [attr.rows]="element.rows" [ngClass]="element.classes?.element"></textarea> <div *ngSwitchCase="'radio'" [ngClass]="element.classes?.element"> <div class="radio" *ngFor="let o of element.options"> <input [type]="element.type" [formControlName]="element.key" [name]="element.key" [value]="o.value" [checked]="element.value === o.value" (click)="setRadio(o)"> <span>{{o.name ? o.name : o.value}}</span> </div> </div> <input *ngSwitchDefault [formControlName]="element.key" [attr.placeholder]="element.placeholder" [type]="element.type" (ngModelChange)="onValueChange($event)" [ngClass]="element.classes?.element" [id]="element.key"> </div> <div *ngIf="settings.showValidation" [hidden]="showErrorMsg"> <span *ngFor="let e of errors()" [ngClass]="element.classes?.error">{{e}}</span> </div> </div> ` },] }, ]; /** * @nocollapse */ LCElementComponent.ctorParameters = () => []; LCElementComponent.propDecorators = { 'toSet': [{ type: HostBinding, args: ['class',] },], 'info': [{ type: Input },], 'valueChange': [{ type: Output },], }; class LCFormsModule { } LCFormsModule.decorators = [ { type: NgModule, args: [{ imports: [CommonModule, ReactiveFormsModule], declarations: [LCFormComponent, LCElementComponent], exports: [LCFormComponent, LCElementComponent], providers: [LCFormService] },] }, ]; /** * @nocollapse */ LCFormsModule.ctorParameters = () => []; /** * Generated bundle index. Do not edit. */ export { LCFormsModule, LCElementComponent as ɵc, LCFormComponent as ɵa, LCFormService as ɵb }; //# sourceMappingURL=lc-forms.js.map