angular-formio
Version:
The Form.io dynamic form and data management system for Angular.
272 lines (249 loc) • 8.04 kB
text/typescript
import { Component, Input, Output, EventEmitter, OnInit, OnChanges, ViewEncapsulation, Optional, ElementRef, ViewChild } from '@angular/core';
import { FormioService } from './formio.service';
import { FormioLoader } from './formio.loader';
import { FormioAlerts, FormioAlert } from './formio.alerts';
import { FormioAppConfig } from './formio.config';
import { FormioForm, FormioOptions, FormioError, FormioRefreshValue } from './formio.common';
/* tslint:disable */
const Formio = require('formiojs/full');
const _each = require('lodash/each');
/* tslint:enable */
export class FormioComponent implements OnInit, OnChanges {
public ready: Promise<boolean>;
public readyResolve: any;
form: FormioForm;
submission: any = {};
src: string;
url: string;
service: FormioService;
options: FormioOptions;
readOnly: boolean = false;
hideComponents: string[];
refresh: EventEmitter<FormioRefreshValue>;
error: EventEmitter<any>;
success: EventEmitter<object>;
render: EventEmitter<object>;
customEvent: EventEmitter<object>;
submit: EventEmitter<object>;
prevPage: EventEmitter<object>;
nextPage: EventEmitter<object>;
beforeSubmit: EventEmitter<object>;
change: EventEmitter<object>;
invalid: EventEmitter<boolean>;
errorChange: EventEmitter<any>;
formLoad: EventEmitter<any>;
formioElement:ElementRef;
private formio: any;
private initialized: boolean;
constructor(
private loader: FormioLoader,
private alerts: FormioAlerts,
private config: FormioAppConfig
) {
if (this.config) {
Formio.Formio.setBaseUrl(this.config.apiUrl);
Formio.Formio.setAppUrl(this.config.appUrl);
}
else {
console.warn('You must provide an AppConfig within your application!');
}
this.ready = new Promise((resolve: any) => {
this.readyResolve = resolve;
});
this.beforeSubmit = new EventEmitter();
this.prevPage = new EventEmitter();
this.nextPage = new EventEmitter();
this.submit = new EventEmitter();
this.errorChange = new EventEmitter();
this.invalid = new EventEmitter();
this.change = new EventEmitter();
this.customEvent = new EventEmitter();
this.render = new EventEmitter();
this.formLoad = new EventEmitter();
this.initialized = false;
this.alerts.alerts = [];
}
setForm(form: FormioForm) {
this.form = form;
// Only initialize a single formio instance.
if (this.formio) {
this.formio.form = this.form;
return;
}
// Create the form.
return Formio.Formio.createForm(this.formioElement.nativeElement, this.form, {
noAlerts: true,
readOnly: this.readOnly,
i18n: this.options.i18n
}).then((formio: any) => {
this.formio = formio;
if (this.url) {
this.formio.url = this.url;
}
if (this.src) {
this.formio.url = this.src;
}
this.formio.nosubmit = true;
this.formio.on('prevPage', (data: any) => this.onPrevPage(data));
this.formio.on('nextPage', (data: any) => this.onNextPage(data));
this.formio.on('change', (value: any) => this.change.emit(value));
this.formio.on('customEvent', (event: any) => this.customEvent.emit(event));
this.formio.on('submit', (submission: any) => this.submitForm(submission));
this.formio.on('error', (err: any) => this.onError(err));
this.formio.on('render', () => this.render.emit());
this.formio.on('formLoad', (loadedForm: any) => this.formLoad.emit(loadedForm));
this.loader.loading = false;
this.readyResolve();
});
}
initialize() {
if (this.initialized) {
return;
}
this.options = Object.assign({
errors: {
message: 'Please fix the following errors before submitting.'
},
alerts: {
submitMessage: 'Submission Complete.'
},
hooks: {
beforeSubmit: null
}
}, this.options);
this.initialized = true;
}
ngOnInit() {
this.initialize();
if (this.refresh) {
this.refresh.subscribe((refresh: FormioRefreshValue) => this.onRefresh(refresh));
}
if (this.error) {
this.error.subscribe((err: any) => this.onError(err))
}
if (this.success) {
this.success.subscribe((message: string) => {
this.alerts.setAlert({
type: 'success',
message: message || this.options.alerts.submitMessage
});
});
}
if (this.src) {
if (!this.service) {
this.service = new FormioService(this.src);
}
this.loader.loading = true;
this.service.loadForm().subscribe((form: FormioForm) => {
if (form && form.components) {
this.setForm(form);
}
// if a submission is also provided.
if (!this.submission && this.service.formio.submissionId) {
this.service.loadSubmission().subscribe((submission: any) => {
this.submission = this.formio.submission = submission;
}, (err) => this.onError(err));
}
}, (err) => this.onError(err));
}
}
onRefresh(refresh: FormioRefreshValue) {
switch (refresh.property) {
case 'submission':
this.formio.submission = refresh.value;
break;
case 'form':
this.formio.form = refresh.value;
break;
}
}
ngOnChanges(changes: any) {
this.initialize();
if (changes.form && changes.form.currentValue) {
this.setForm(changes.form.currentValue);
}
this.ready.then(() => {
if (changes.submission && changes.submission.currentValue) {
this.formio.submission = changes.submission.currentValue;
}
if (changes.hideComponents) {
this.formio.hideComponents(changes.hideComponents.currentValue);
}
});
}
onPrevPage(data: any) {
this.alerts.setAlerts([]);
this.prevPage.emit(data)
}
onNextPage(data: any) {
this.alerts.setAlerts([]);
this.nextPage.emit(data)
}
onSubmit(submission: any, saved: boolean) {
if (saved) {
this.formio.emit('submitDone', submission);
}
this.submit.emit(submission);
if (!this.success) {
this.alerts.setAlert({
type: 'success',
message: this.options.alerts.submitMessage
});
}
}
onError(err: any) {
this.alerts.setAlerts([]);
if (!err) {
return;
}
// Make sure it is an array.
err = (err instanceof Array) ? err : [err];
// Emit these errors again.
this.errorChange.emit(err);
// Iterate through each one and set the alerts array.
_each(err, (error: any) => {
this.alerts.setAlert({
type: 'danger',
message: error.message || error.toString()
});
});
}
submitExecute(submission: object) {
if (this.service) {
this.service.saveSubmission(submission).subscribe(
(sub: {}) => this.onSubmit(sub, true),
(err) => this.onError(err)
);
}
else {
this.onSubmit(submission, false);
}
}
submitForm(submission: any) {
this.beforeSubmit.emit(submission);
// if they provide a beforeSubmit hook, then allow them to alter the submission asynchronously
// or even provide a custom Error method.
if (this.options.hooks.beforeSubmit) {
this.options.hooks.beforeSubmit(submission, (err: FormioError, sub: object) => {
if (err) {
this.onError(err);
return;
}
this.submitExecute(sub);
});
}
else {
this.submitExecute(submission);
}
}
}