UNPKG

ngx-mat-dynamic-form-builder

Version:

Build dynamic forms in Angular Material using Reactive forms.

793 lines (766 loc) 40.2 kB
import { ɵɵdefineInjectable, Injectable, Component, EventEmitter, Input, Output, ViewChild, NgModule } from '@angular/core'; import { FormControl, Validators, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { startWith, map, tap } from 'rxjs/operators'; import { isString } from 'lodash'; import { ENTER, COMMA } from '@angular/cdk/keycodes'; import { DateAdapter } from '@angular/material/core'; import { CommonModule } from '@angular/common'; import { FlexLayoutModule } from '@angular/flex-layout'; import { MatChipsModule } from '@angular/material/chips'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatInputModule } from '@angular/material/input'; import { MatIconModule } from '@angular/material/icon'; import { MatSelectModule } from '@angular/material/select'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatButtonModule } from '@angular/material/button'; import { MatBadgeModule } from '@angular/material/badge'; class NgxMatDynamicFormBuilderService { constructor() { } } NgxMatDynamicFormBuilderService.ɵprov = ɵɵdefineInjectable({ factory: function NgxMatDynamicFormBuilderService_Factory() { return new NgxMatDynamicFormBuilderService(); }, token: NgxMatDynamicFormBuilderService, providedIn: "root" }); NgxMatDynamicFormBuilderService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; NgxMatDynamicFormBuilderService.ctorParameters = () => []; class NgxMatDynamicFormBuilderComponent { constructor() { } ngOnInit() { } } NgxMatDynamicFormBuilderComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-mat-dynamic-form-builder', template: ` <p> ngx-mat-dynamic-form-builder works! </p> ` },] } ]; NgxMatDynamicFormBuilderComponent.ctorParameters = () => []; class AutoCompleteComponent { constructor() { this.options = []; this.hint = ''; this.appearance = 'standard'; this.disabled = false; this.autoClear = false; this.output = new EventEmitter(); } ngOnInit() { this.setupValidators(); } ngOnChanges(changes) { if (changes.options && this.options) { if (!this.stateCtrl) this.setupValidators(); this.filteredOptions = this.stateCtrl.valueChanges .pipe(startWith(''), map(state => state ? this._filterOptions(state) : this.options.slice())); if (this.defaultOption && this.defaultOptionKey) { this.stateCtrl.setValue(this.options.find(o => o[this.defaultOptionKey] === this.defaultOption)); } } } setupValidators() { if (this.stateCtrl) return; if (this.validators) { let isRequired = false; this.validators.forEach(vd => { if (vd.name === 'required') isRequired = true; }); if (isRequired) { this.stateCtrl = new FormControl(null, [Validators.required, this.valueSelected()]); } else { this.stateCtrl = new FormControl(null, [this.valueSelected()]); } } else { this.stateCtrl = new FormControl(null, [this.valueSelected()]); } } displayFn(value) { if (value) return value[this.displayKey]; } setValue(event) { this.output.emit(event.option.value); if (this.autoClear) { this.stateCtrl.reset(); } } clearValue() { this.output.emit(undefined); this.stateCtrl.reset(); } _filterOptions(value) { if (isString(value) && value.length >= 1) { const filterValue = value.toLowerCase(); return this.options.filter(state => state[this.filterKey ? this.filterKey : this.displayKey].toLowerCase().includes(filterValue)); } return this.options; } valueSelected() { return (c) => { // if value is set and it is not an object, valid option not selected if (c.value && typeof c.value !== 'object') { return { match: true }; } else { return null; } }; } } AutoCompleteComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-mat-auto-complete', template: "<mat-form-field [appearance]=\"appearance\" fxFlex>\r\n <mat-label>{{label}}</mat-label>\r\n <input matInput [placeholder]=\"placeholder\" [readonly]=\"disabled\" aria-label=\"AutoComplete\" [matAutocomplete]=\"auto\"\r\n [formControl]=\"stateCtrl\">\r\n <mat-autocomplete #auto=\"matAutocomplete\" autoActiveFirstOption (optionSelected)=\"setValue($event)\"\r\n [displayWith]=\"displayFn.bind(this)\">\r\n <mat-option *ngFor=\"let option of filteredOptions | async\" [value]=\"option\">\r\n <span>{{option[displayKey]}}</span>\r\n </mat-option>\r\n </mat-autocomplete>\r\n <button mat-button *ngIf=\"stateCtrl.value && !disabled\" matSuffix mat-icon-button aria-label=\"Clear\"\r\n (click)=\"clearValue()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n <mat-hint>{{hint}}</mat-hint>\r\n <mat-error *ngIf=\"!stateCtrl.valid && stateCtrl.touched\">Select valid option</mat-error>\r\n</mat-form-field>", styles: [""] },] } ]; AutoCompleteComponent.ctorParameters = () => []; AutoCompleteComponent.propDecorators = { options: [{ type: Input }], defaultOption: [{ type: Input }], defaultOptionKey: [{ type: Input }], label: [{ type: Input }], placeholder: [{ type: Input }], displayKey: [{ type: Input }], filterKey: [{ type: Input }], hint: [{ type: Input }], appearance: [{ type: Input }], disabled: [{ type: Input }], autoClear: [{ type: Input }], validators: [{ type: Input }], output: [{ type: Output }] }; class ChipSelectorComponent { constructor() { this.options = []; this.hint = ""; this.appearance = 'standard'; this.disabled = false; this.customChip = false; this.output = new EventEmitter(); this.visible = true; this.selectable = true; this.separatorKeysCodes = [ENTER, COMMA]; this.selectedObjects = []; } ngOnInit() { this.setupValidators(); } ngOnChanges(changes) { if (changes.options && this.options) { if (!this.formControl) this.setupValidators(); this.filteredObjects = this.formControl.valueChanges.pipe(startWith([]), map((obj) => { return obj ? this._filter(obj) : this.options.slice(); })); if (this.defaultOptions && this.defaultOptionsKey) { this.addDefaultSelected(this.defaultOptions); } } } setupValidators() { if (this.formControl) return; if (this.validators) { let isRequired = false; this.validators.forEach(vd => { if (vd.name === 'required') isRequired = true; }); if (isRequired) { this.formControl = new FormControl(this.selectedObjects, [Validators.required, this.valueSelected()]); } else { this.formControl = new FormControl(this.selectedObjects, [this.valueSelected()]); } } else if (!this.customChip) { this.formControl = new FormControl(this.selectedObjects, [this.valueSelected()]); } else { this.formControl = new FormControl(); } } add(event) { // Add fruit only when MatAutocomplete is not open // To make sure this does not conflict with OptionSelected Event if (!this.matAutocomplete.isOpen) { const input = event.input; const value = event.value; if (this.customChip && (value || '').trim()) { this.selectedObjects.push({ [this.displayKey]: value.trim() }); this.output.emit(this.selectedObjects); } // Reset the input value if (input) { input.value = ''; } } this.formControl.setValue(this.selectedObjects); this.formControl.updateValueAndValidity(); } remove(item) { this.updateFilteredObjects(); const index = this.selectedObjects.indexOf(item); if (index >= 0) { this.selectedObjects.splice(index, 1); this.output.emit(this.selectedObjects); } this.formControl.updateValueAndValidity(); } updateFilteredObjects() { this.filteredObjects = this.filteredObjects.pipe(map(data => data.filter(obj => !this.selectedObjects.includes(obj)))); } selected(event) { this.selectedObjects.push(event.option.value); this.output.emit(this.selectedObjects); this.updateFilteredObjects(); this.formInput.nativeElement.value = ''; this.formInput.nativeElement.blur(); this.formControl.setValue(this.selectedObjects); } addDefaultSelected(values) { if (!Array.isArray(values)) { console.error('Default values not an array'); return; } this.selectedObjects = this.options.filter(i => values.some(t => t === i[this.defaultOptionsKey])); this.output.emit(this.selectedObjects); this.updateFilteredObjects(); this.formControl.setValue(this.selectedObjects); } _filter(value) { if (isString(value) && value.length >= 1) { let filterValue = value.toLowerCase(); return this.options.filter(obj => obj[this.filterKey ? this.filterKey : this.displayKey]. toLowerCase().includes(filterValue)); } return this.options; } valueSelected() { return (c) => { // if value is set and it is not an object, valid option not selected if (c.value && typeof c.value !== 'object') { return { match: true }; } else { return null; } }; } } ChipSelectorComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-mat-chip-selector', template: "<mat-form-field [appearance]=\"appearance\" fxFlex>\r\n <mat-label>{{label}}</mat-label>\r\n <mat-chip-list #chipList>\r\n <mat-chip *ngFor=\"let obj of selectedObjects\" [selectable]=\"selectable\" [removable]=\"!disabled\"\r\n (removed)=\"remove(obj)\">\r\n {{obj[displayKey]}}\r\n <mat-icon matChipRemove *ngIf=\"!disabled\">cancel</mat-icon>\r\n </mat-chip>\r\n <input [placeholder]=\"placeholder\" [readonly]=\"disabled\" #formInput [matAutocomplete]=\"auto\"\r\n [matChipInputFor]=\"chipList\" [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\r\n (matChipInputTokenEnd)=\"add($event)\" [formControl]=\"formControl\">\r\n <mat-error *ngIf=\"!formControl.valid && formControl.touched\">Select valid option</mat-error>\r\n </mat-chip-list>\r\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selected($event)\">\r\n <mat-option *ngFor=\"let obj of filteredObjects | async\" [value]=\"obj\">\r\n {{obj[displayKey]}}\r\n </mat-option>\r\n </mat-autocomplete>\r\n <mat-hint>{{hint}} </mat-hint>\r\n</mat-form-field>", styles: [""] },] } ]; ChipSelectorComponent.propDecorators = { options: [{ type: Input }], defaultOptions: [{ type: Input }], defaultOptionsKey: [{ type: Input }], label: [{ type: Input }], placeholder: [{ type: Input }], displayKey: [{ type: Input }], filterKey: [{ type: Input }], hint: [{ type: Input }], appearance: [{ type: Input }], disabled: [{ type: Input }], customChip: [{ type: Input }], validators: [{ type: Input }], output: [{ type: Output }], formInput: [{ type: ViewChild, args: ['formInput',] }], matAutocomplete: [{ type: ViewChild, args: ['auto',] }] }; class QuestionControlService { constructor() { } toFormGroup(questions) { let group = {}; questions.some(question => { if (question.controlType === 'spacer') { return; } group[question.key] = question.validators ? new FormControl({ value: question.value !== undefined || question.value !== null ? question.value : undefined, disabled: question.disabled }, question.validators) : new FormControl({ value: question.value !== undefined || question.value !== null ? question.value : undefined, disabled: question.disabled }); }); return new FormGroup(group); } } QuestionControlService.decorators = [ { type: Injectable } ]; QuestionControlService.ctorParameters = () => []; class DynamicFormComponent { constructor(qcs) { this.qcs = qcs; this.questions = []; this.emitOnlyOnChange = false; this.formResult = new EventEmitter(); } ngOnInit() { if (!this.questions || this.questions.length === 0) { console.error('Questions are null or empty.'); return; } this.form = this.qcs.toFormGroup(this.questions); // Emit if the form is valid from begining but not if on change flag is set. if (!this.emitOnlyOnChange && this.form.valid) { this.emitForm(); } this._buttonText = this.buttonText || 'Save'; this.prepareConditionalControls(); this.prepareFilteredOptions(); this.form.statusChanges.subscribe(status => { if (status === 'VALID') { this.emitForm(); } else { this.formResult.emit(null); } ; }); } emitForm() { let validForm = this.form.getRawValue(); this.questions.forEach((q) => { if (q.type && q.type === 'number') { if (validForm[q.key]) validForm[q.key] = Number(validForm[q.key]); } }); this.formResult.emit(validForm); } prepareConditionalControls() { this.changeSubscriptions = []; // Listen for changes on other controlls this.questions.forEach(q => { if (q.conditional) { // Subscribe to changes const targetControl = this.form.controls[q.conditional.controlKey]; this.changeSubscriptions.push(targetControl.valueChanges.subscribe(value => { if (Array.isArray(value)) { value.includes(q.conditional.value) ? q.show = true : q.show = false; } else { q.conditional.value === value ? q.show = true : q.show = false; } })); // If values are set check them now if (Array.isArray(targetControl.value)) { targetControl.value.includes(q.conditional.value) ? q.show = true : q.show = false; } else if (targetControl.value && targetControl.value === q.conditional.value) { q.show = true; } } }); } prepareFilteredOptions() { this.filterSubscriptions = []; this.questions.forEach((q) => { if (q.selectionFilter) { const targetControl = this.form.controls[q.selectionFilter.controlKey]; // If the target value changes, subscribe to load new selections this.filterSubscriptions.push(targetControl.valueChanges.subscribe(value => { q.selectionFilter.options$(value).subscribe(res => { q.options$.next(res); }); })); // if target is set, then load them immediately if (targetControl.value) { q.selectionFilter.options$(targetControl.value).subscribe(res => { q.options$.next(res); }); } } }); } ngOnDestroy() { if (this.changeSubscriptions) { this.changeSubscriptions.forEach(s => { s.unsubscribe; }); } if (this.filterSubscriptions) { this.filterSubscriptions.forEach(s => { s.unsubscribe; }); } } } DynamicFormComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-mat-dynamic-form', template: "<form [formGroup]=\"form\" fxLayout=\"column\">\n <div fxLayout=\"row wrap\" fxLayoutAlign=\"start center\">\n <div *ngFor=\"let question of questions; let i = index\" [fxFlex.xs]=\"question.xsFlex\"\n [fxFlex.gt-xs]=\"question.flex\">\n <ngx-mat-dynamic-form-question *ngIf=\"question.show\" [question]=\"question\" [form]=\"form\">\n </ngx-mat-dynamic-form-question>\n </div>\n <ng-content></ng-content>\n </div>\n</form>", providers: [QuestionControlService], styles: [""] },] } ]; DynamicFormComponent.ctorParameters = () => [ { type: QuestionControlService } ]; DynamicFormComponent.propDecorators = { questions: [{ type: Input }], buttonText: [{ type: Input }], emitOnlyOnChange: [{ type: Input }], formResult: [{ type: Output }] }; class DynamicFormQuestionComponent { constructor(adapter) { this.adapter = adapter; this.loading = false; this.adapter.setLocale('en-GB'); } get isValid() { return this.form.controls[this.question.key].valid; } ngOnInit() { if (this.question.selectionFilter) { console.log('TODO: Do some loading here...'); } else if (this.question.options$) { this.loading = true; this.question.options$ = this.question.options$.pipe(tap(_ => setTimeout(() => { this.loading = false; }))); } } setMutlipleValues(event) { if (this.question.customChip) { this.form.controls[this.question.key].setValue(event); } else { this.form.controls[this.question.key].setValue(this.question.emitObject ? event : event.map(val => val[this.question.selection.key])); } } setSingleValue(event) { // Clear input of auto complete if (!event) { this.form.controls[this.question.key].setValue(undefined); } else { this.form.controls[this.question.key].setValue(this.question.emitObject ? event : event[this.question.selection.key]); } } dateTimeChange(event) { if (this.question.hourControl.value) { event.value.setHours(this.question.hourControl.value); } if (this.question.minuteControl.value) { event.value.setMinutes(this.question.minuteControl.value); } this.form.controls[this.question.key].setValue(event.value); } dateChange(event) { this.form.controls[this.question.key].setValue(event.value); } setFile(file) { this.form.controls[this.question.key].setValue(file); } } DynamicFormQuestionComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-mat-dynamic-form-question', template: "<div [formGroup]=\"form\" fxFlex style=\"margin: 5px;\" fxLayout=\"row\" fxLayoutAlign=\"center center\">\r\n\r\n <ng-container [ngSwitch]=\"question.controlType\">\r\n\r\n <span *ngSwitchCase=\"'spacer'\" fxFlex></span>\r\n\r\n <mat-form-field [appearance]=\"question.appearance\" *ngSwitchCase=\"'textbox'\" fxFlex>\r\n <mat-label>{{question.label}}</mat-label>\r\n <span *ngIf=\"question.prefix\" matPrefix>{{question.prefix}}&nbsp;</span>\r\n <mat-icon *ngIf=\"question.prefixIcon\" matPrefix>{{question.prefixIcon}}</mat-icon>\r\n <input matInput [placeholder]=\"question.placeholder\" [formControlName]=\"question.key\" [type]=\"question.type\">\r\n <mat-hint *ngIf=\"question.hint\">{{question.hint}}</mat-hint>\r\n <mat-icon *ngIf=\"question.suffixIcon\" matSuffix>{{question.suffixIcon}}</mat-icon>\r\n <span *ngIf=\"question.suffix\" matSuffix>&nbsp;{{question.suffix}}</span>\r\n <mat-error>\r\n <ngx-mat-print-input-error [control]=\"form.controls[question.key]\"> </ngx-mat-print-input-error>\r\n </mat-error>\r\n </mat-form-field>\r\n\r\n <mat-form-field [appearance]=\"question.appearance\" *ngSwitchCase=\"'textarea'\" fxFlex>\r\n <mat-label>{{question.label}}</mat-label>\r\n <span *ngIf=\"question.prefix\" matPrefix>{{question.prefix}}&nbsp;</span>\r\n <mat-icon *ngIf=\"question.prefixIcon\" matPrefix>{{question.prefixIcon}}</mat-icon>\r\n <textarea matInput [placeholder]=\"question.placeholder\" [formControlName]=\"question.key\" [type]=\"question.type\"\r\n [cdkAutosizeMinRows]=\"question.minRows\" [cdkAutosizeMaxRows]=\"question.maxRows\"\r\n [cdkTextareaAutosize]=\"question.autoSize\"></textarea>\r\n <mat-hint *ngIf=\"question.hint\">{{question.hint}}</mat-hint>\r\n <mat-icon *ngIf=\"question.suffixIcon\" matSuffix>{{question.suffixIcon}}</mat-icon>\r\n <span *ngIf=\"question.suffix\" matSuffix>&nbsp;{{question.suffix}}</span>\r\n <mat-error>\r\n <ngx-mat-print-input-error [control]=\"form.controls[question.key]\"> </ngx-mat-print-input-error>\r\n </mat-error>\r\n </mat-form-field>\r\n\r\n <mat-form-field [appearance]=\"question.appearance\" *ngSwitchCase=\"'dropdown'\" fxFlex>\r\n <mat-label>{{question.label}}</mat-label>\r\n <mat-select [formControlName]=\"question.key\">\r\n <ng-container *ngIf=\"question.options$\">\r\n <mat-option *ngIf=\"question.defaultValue\">None</mat-option>\r\n <mat-option *ngFor=\"let opt of question.options$ | async\" [value]=\"opt[question.selection.key]\">\r\n {{opt[question.selection.value]}}\r\n </mat-option>\r\n </ng-container>\r\n <ng-container *ngIf=\"question.options\">\r\n <mat-option *ngFor=\"let opt of question.options\" [value]=\"opt[question.selection.key]\">\r\n {{opt[question.selection.value]}}\r\n </mat-option>\r\n </ng-container>\r\n </mat-select>\r\n <mat-hint *ngIf=\"question.hint\">{{question.hint}}</mat-hint>\r\n <mat-error>\r\n <ngx-mat-print-input-error [control]=\"form.controls[question.key]\"> </ngx-mat-print-input-error>\r\n </mat-error>\r\n </mat-form-field>\r\n\r\n <div *ngSwitchCase=\"'chipSelector'\" fxFlex>\r\n <ngx-mat-chip-selector [options]=\"question.options$ | async\" [defaultOptions]=\"question.value\"\r\n [defaultOptionsKey]=\"question.selection.key\" [placeholder]=\"question.placeholder\" [disabled]=\"question.disabled\"\r\n [label]=\"question.label\" [displayKey]=\"question.selection.value\" [filterKey]=\"question.selection.value\"\r\n [appearance]=\"question.appearance\" [hint]=\"question.hint\" [validators]=\"question.validators\"\r\n [customChip]=\"question.customChip\" (output)=\"setMutlipleValues($event)\" fxFlex>\r\n </ngx-mat-chip-selector>\r\n </div>\r\n\r\n <div *ngSwitchCase=\"'autoComplete'\" fxFlex>\r\n <ngx-mat-auto-complete [options]=\"question.options$ | async\" [defaultOption]=\"question.value\"\r\n [defaultOptionKey]=\"question.selection.key\" [placeholder]=\"question.placeholder\" [disabled]=\"question.disabled\"\r\n [label]=\"question.label\" [displayKey]=\"question.selection.value\" [filterKey]=\"question.selection.value\"\r\n [appearance]=\"question.appearance\" [hint]=\"question.hint\" [validators]=\"question.validators\"\r\n (output)=\"setSingleValue($event)\" [autoClear]=\"question.autoClear\" fxFlex>\r\n </ngx-mat-auto-complete>\r\n </div>\r\n\r\n <div *ngSwitchCase=\"'date-time'\" fxLayout=\"row wrap\" fxFlex>\r\n <mat-form-field fxFlex.gt-xs fxFlex [appearance]=\"question.appearance\">\r\n <mat-label>{{question.label}}</mat-label>\r\n <input matInput [min]=\"question.minDate\" [max]=\"question.maxDate\" [matDatepicker]=\"picker1\"\r\n (dateChange)=\"dateTimeChange($event)\" [placeholder]=\"question.placeholder\"\r\n [formControl]=\"question.dateControl\" readonly>\r\n <mat-datepicker-toggle matSuffix [for]=\"picker1\"></mat-datepicker-toggle>\r\n <mat-datepicker #picker1 [disabled]=\"question.disabled\"></mat-datepicker>\r\n <mat-error>\r\n <ngx-mat-print-input-error [control]=\"form.controls[question.key]\"> </ngx-mat-print-input-error>\r\n </mat-error>\r\n </mat-form-field>\r\n <mat-form-field fxFlex.gt-xs=\"20\" fxFlex [appearance]=\"question.appearance\" style=\"margin-left: 5px;\">\r\n <mat-label>Hour</mat-label>\r\n <input type=\"number\" matInput [formControl]=\"question.hourControl\" placeholder=\"Hour\">\r\n </mat-form-field>\r\n <mat-form-field fxFlex.gt-xs=\"20\" fxFlex [appearance]=\"question.appearance\" style=\"margin-left: 5px;\">\r\n <mat-label>Minute</mat-label>\r\n <input type=\"number\" matInput [formControl]=\"question.minuteControl\" placeholder=\"Minute\">\r\n </mat-form-field>\r\n </div>\r\n\r\n <div *ngSwitchCase=\"'date'\" fxLayout=\"row wrap\" fxFlex>\r\n <mat-form-field fxFlex.gt-xs fxFlex [appearance]=\"question.appearance\">\r\n <mat-label>{{question.label}}</mat-label>\r\n <input matInput [min]=\"question.minDate\" [max]=\"question.maxDate\" [matDatepicker]=\"picker1\"\r\n (dateChange)=\"dateChange($event)\" [placeholder]=\"question.placeholder\" [formControl]=\"question.dateControl\"\r\n readonly>\r\n <mat-datepicker-toggle matSuffix [for]=\"picker1\"></mat-datepicker-toggle>\r\n <mat-datepicker #picker1 [disabled]=\"question.disabled\"></mat-datepicker>\r\n <mat-error>\r\n <ngx-mat-print-input-error [control]=\"form.controls[question.key]\"> </ngx-mat-print-input-error>\r\n </mat-error>\r\n </mat-form-field>\r\n </div>\r\n\r\n <div *ngSwitchCase=\"'checkbox'\" fxFlex>\r\n <mat-checkbox [labelPosition]=\"question.labelPosition\" [checked]=\"question.checked\" [color]=\"question.color\"\r\n [formControlName]=\"question.key\">{{question.label}}</mat-checkbox>\r\n <mat-error>\r\n <ngx-mat-print-input-error [control]=\"form.controls[question.key]\"> </ngx-mat-print-input-error>\r\n </mat-error>\r\n </div>\r\n\r\n <div *ngSwitchCase=\"'file-upload'\" fxFlex>\r\n <ngx-mat-file-upload [prefixIcon]=\"question.prefixIcon\" [label]=\"question.label\" [color]=\"question.color\"\r\n [buttonType]=\"question.buttonType\" (file)=\"setFile($event)\">\r\n </ngx-mat-file-upload>\r\n </div>\r\n\r\n </ng-container>\r\n <div *ngIf=\"loading\" style=\"margin-left: 5px;\">\r\n <mat-spinner style=\"zoom:0.24\"></mat-spinner>\r\n </div>\r\n</div>", styles: [""] },] } ]; DynamicFormQuestionComponent.ctorParameters = () => [ { type: DateAdapter } ]; DynamicFormQuestionComponent.propDecorators = { question: [{ type: Input }], form: [{ type: Input }] }; class PrintInputErrorComponent { constructor() { this.console = console; } } PrintInputErrorComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-mat-print-input-error', template: "<div class=\"text-danger\" *ngIf=\"control && control.errors && (control.dirty || control.touched)\">\r\n\r\n <div *ngIf=\"control.errors.required\">\r\n <small>Field is required</small>\r\n </div>\r\n\r\n <div *ngIf=\"control.errors.max\"><small>Maximum value is {{control.errors.max.max}} </small></div>\r\n <div *ngIf=\"control.errors.min\"><small>Minimum value is {{control.errors.min.min}} </small></div>\r\n\r\n <div *ngIf=\"control.errors.maxlength\"><small>Maximum number of characters is\r\n {{control.errors.maxlength.requiredLength}} </small></div>\r\n <div *ngIf=\"control.errors.minlength\"><small>Minimum number of characters is\r\n {{control.errors.minlength.requiredLength}} </small></div>\r\n\r\n <div *ngIf=\"control.errors.email\"><small>Invalid email address</small></div>\r\n\r\n\r\n <div *ngIf=\"control.errors.unique\"><small>{{control.errors.unique}}</small></div>\r\n <div *ngIf=\"control.errors.lessThen\"><small>{{control.errors.lessThen}}</small></div>\r\n <div *ngIf=\"control.errors.greaterThan\"><small>{{control.errors.greaterThan}}</small></div>\r\n <div *ngIf=\"control.errors.mobile\"><small>{{control.errors.mobile}}</small></div>\r\n <div *ngIf=\"control.errors.confirmPassword\"><small>{{control.errors.confirmPassword}}</small></div>\r\n</div>", styles: [""] },] } ]; PrintInputErrorComponent.propDecorators = { control: [{ type: Input, args: ["control",] }] }; class FileUploadComponent { constructor() { this.file = new EventEmitter(); } ngOnInit() { } processFile(event) { this.fileSelected = event.target.files[0]; this.file.emit(this.fileSelected); } } FileUploadComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-mat-file-upload', template: "<ng-container *ngIf=\"buttonType === 'icon'; else normalButton;\">\n <button mat-icon-button (click)=\"fileInput.click()\">\n <mat-icon matBadge=\"1\" [matBadgeHidden]=\"!fileSelected\" matBadgeSize=\"small\" matBadgeColor=\"accent\">\n {{prefixIcon}}</mat-icon>\n <input #fileInput type=\"file\" (change)=\"processFile($event)\" style=\"display:none;\" />\n </button>\n</ng-container>\n<ng-template #normalButton>\n <button mat-flat-button [color]=\"color ? color : 'primary'\" (click)=\"fileInput.click()\">\n <mat-icon *ngIf=\"prefixIcon && !fileSelected\" style=\"margin-left: -8px;\">{{prefixIcon}}</mat-icon>\n <mat-icon *ngIf=\"fileSelected\">check</mat-icon>\n <span>{{label}}</span>\n <input #fileInput type=\"file\" (change)=\"processFile($event)\" style=\"display:none;\" />\n </button>\n</ng-template>", styles: [""] },] } ]; FileUploadComponent.ctorParameters = () => []; FileUploadComponent.propDecorators = { buttonType: [{ type: Input }], prefixIcon: [{ type: Input }], suffixIcon: [{ type: Input }], label: [{ type: Input }], color: [{ type: Input }], file: [{ type: Output }] }; class NgxMatDynamicFormBuilderModule { } NgxMatDynamicFormBuilderModule.decorators = [ { type: NgModule, args: [{ declarations: [ NgxMatDynamicFormBuilderComponent, AutoCompleteComponent, ChipSelectorComponent, DynamicFormComponent, DynamicFormQuestionComponent, PrintInputErrorComponent, FileUploadComponent ], imports: [ CommonModule, FormsModule, ReactiveFormsModule, FlexLayoutModule, MatInputModule, MatChipsModule, MatFormFieldModule, MatAutocompleteModule, MatProgressSpinnerModule, MatDatepickerModule, MatIconModule, MatSelectModule, MatCheckboxModule, MatButtonModule, MatBadgeModule ], exports: [ AutoCompleteComponent, ChipSelectorComponent, DynamicFormComponent, DynamicFormQuestionComponent, PrintInputErrorComponent ] },] } ]; /** * Base question with no mat form field */ class Question { constructor(options = {}) { this.value = options.value; this.key = options.key || ''; this.label = options.label || ''; this.controlType = options.controlType || ''; this.validators = options.validators || null; this.flex = options.flex || 100; this.xsFlex = options.xsFlex || 100; this.disabled = options.disabled || false; this.conditional = options.conditional; this.conditional ? this.show = false : this.show = true; } } /** * Base for all mat form field questions: * Auto complete * Chip Selector * Date time * Date * Dropdown * Select * Text area * Text Box */ class QuestionBase extends Question { constructor(options = {}) { super(options); this.hint = options.hint || ''; this.placeholder = options.placeholder || ''; this.appearance = options.appearance || 'standard'; this.validators = options.validators || null; this.prefix = options.prefix; this.suffix = options.suffix; this.prefixIcon = options.prefixIcon; this.suffixIcon = options.suffixIcon; } } /** * Base class for any drop down of multiple select */ class SelectQuestion extends QuestionBase { constructor(options = {}) { super(options); this.options = options['options'] || []; this.options$ = options['options$']; this.selection = options['selection']; this.defaultValue = options['defaultValue'] != undefined ? options['defaultValue'] : false; this.selectionFilter = options['selectionFilter']; this.emitObject = options['emitObject']; } } class AutoCompleteQuestion extends SelectQuestion { constructor(options = {}) { super(options); this.controlType = 'autoComplete'; this.autoClear = options['autoClear'] || false; } } class DropdownQuestion extends SelectQuestion { constructor(options = {}) { super(options); this.controlType = 'dropdown'; } } class ChipSelectorQuestion extends SelectQuestion { constructor(options = {}) { super(options); this.controlType = 'chipSelector'; this.customChip = options['customChip']; } } class TextboxQuestion extends QuestionBase { constructor(options = {}) { super(options); this.controlType = 'textbox'; this.type = options['type'] || ''; } } class CheckboxQuestion extends Question { constructor(options = {}) { super(options); this.controlType = 'checkbox'; this.checked = options['value'] || options['value'] === true ? true : false; this.value = this.checked; this.color = options['color'] || 'primary'; this.labelPosition = options['labelPosition'] || 'after'; } } class TextAreaQuestion extends QuestionBase { constructor(options = {}) { super(options); this.controlType = 'textarea'; this.type = options['type'] || ''; this.maxRows = options['maxRows'] || 5; this.minRows = options['minRows'] || 2; this.autoSize = options['autoSize'] || true; } } class DateQuestion extends QuestionBase { constructor(options = {}) { super(options); this.controlType = 'date'; this.dateControl = new FormControl(); this.maxDate = options['maxDate']; this.minDate = options['minDate']; if (options['value']) { this.dateControl.setValue(options['value']); } } } class DateTimeQuestion extends DateQuestion { constructor(options = {}) { super(options); this.controlType = 'date-time'; this.hourControl = new FormControl({ value: undefined, disabled: options['disabled'] != undefined ? options['disabled'] : false }, [Validators.min(0), Validators.max(23)]); this.minuteControl = new FormControl({ value: undefined, disabled: options['disabled'] != undefined ? options['disabled'] : false }, [Validators.min(0), Validators.max(59)]); if (this.dateControl.value) { this.hourControl.setValue(this.dateControl.value.getHours()); this.minuteControl.setValue(this.dateControl.value.getMinutes()); } this.hourControl.valueChanges.subscribe(hour => { if (hour !== undefined || hour !== null && this.dateControl.value) { this.dateControl.value.setHours(hour); } }); this.minuteControl.valueChanges.subscribe(min => { if (min !== undefined || min !== null && this.dateControl.value) { this.dateControl.value.setMinutes(min); } }); } } class FileUploadQuestion extends QuestionBase { constructor(options = {}) { super(options); this.controlType = 'file-upload'; this.color = options['color'] || 'primary'; this.buttonType = options['buttonType'] || 'icon'; } } class Spacer extends QuestionBase { constructor(options = {}) { super(options); this.controlType = 'spacer'; this.flex = options['flex'] || 100; } } // @dynamic class FormValidators { static get(validatorString) { const validator = this.validators.find(v => v.name === validatorString); return validator ? validator.validators : []; } } FormValidators.validators = [ { name: 'required', validators: [ Validators.required ] }, { name: 'integer', validators: [ Validators.pattern(/^[0-9]*$/) ] }, { name: 'positiveInteger', validators: [ Validators.min(0), Validators.pattern(/^[0-9]*$/) ] }, { name: 'positiveNumber', validators: [ Validators.min(0), Validators.pattern(/^[0-9]*$/) ] }, { name: 'string', validators: [ Validators.pattern(/^[A-Za-z]+$/) ] } ]; /* * Public API Surface of ngx-mat-dynamic-form-builder */ /** * Generated bundle index. Do not edit. */ export { AutoCompleteComponent, AutoCompleteQuestion, CheckboxQuestion, ChipSelectorComponent, ChipSelectorQuestion, DateQuestion, DateTimeQuestion, DropdownQuestion, DynamicFormComponent, DynamicFormQuestionComponent, FileUploadQuestion, FormValidators, NgxMatDynamicFormBuilderComponent, NgxMatDynamicFormBuilderModule, NgxMatDynamicFormBuilderService, PrintInputErrorComponent, Question, QuestionBase, Spacer, TextAreaQuestion, TextboxQuestion, QuestionControlService as ɵa, FileUploadComponent as ɵb, SelectQuestion as ɵc }; //# sourceMappingURL=ngx-mat-dynamic-form-builder.js.map