novo-elements
Version:
Bullhorn's NOVO Element Repository for Angular 2
557 lines (498 loc) • 18.8 kB
text/typescript
// NG2
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
// Vendor
import 'rxjs/add/operator/map';
// APP
import { NovoFormControl } from './NovoFormControl';
import { NovoControlConfig } from './FormControls';
import { FormUtils } from '../../utils/form-utils/FormUtils';
import { NovoToastService } from '../toast/ToastService';
import { NovoModalService } from '../modal/ModalService';
import { ControlConfirmModal } from './ControlConfirmModal';
import { Helpers } from '../../utils/Helpers';
import { AppBridge } from '../../utils/app-bridge/AppBridge';
import { NovoLabelService } from '../../services/novo-label-service';
export class FieldInteractionApi {
private _globals: any;
private _form: any;
private _currentKey: string;
private _appBridge: AppBridge;
private asyncBlockTimeout: any;
public static FIELD_POSITIONS = {
ABOVE_FIELD: 'ABOVE_FIELD',
BELOW_FIELD: 'BELOW_FIELD',
TOP_OF_FORM: 'TOP_OF_FORM',
BOTTOM_OF_FORM: 'BOTTOM_OF_FORM'
};
constructor(private toaster: NovoToastService, private modalService: NovoModalService,
private formUtils: FormUtils, private http: Http, private labels: NovoLabelService) {
}
set form(form: any) {
this._form = form;
}
get form(): any {
return this._form;
}
set globals(globals: any) {
this._globals = globals;
}
get globals(): any {
return this._globals;
}
set currentKey(key: string) {
this._currentKey = key;
}
get currentKey(): string {
return this._currentKey;
}
set appBridge(appBridge: AppBridge) {
this._appBridge = appBridge;
}
get appBridge(): AppBridge {
return this._appBridge;
}
public isActiveControlValid(): boolean {
return !!this.getValue(this.currentKey);
}
public getActiveControl(): NovoFormControl {
return this.getControl(this.currentKey);
}
public getActiveKey(): string {
return this.currentKey;
}
public getActiveValue(): any {
return this.getValue(this.currentKey);
}
public getActiveInitialValue(): any {
return this.getInitialValue(this.currentKey);
}
public getControl(key: string): NovoFormControl {
if (!key) {
console.error('[FieldInteractionAPI] - invalid or missing "key"'); // tslint:disable-line
return null;
}
let control = this.form.controls[key];
if (!control) {
console.error('[FieldInteractionAPI] - could not find a control in the form by the key --', key); // tslint:disable-line
return null;
}
return (control as NovoFormControl);
}
public getValue(key: string): any {
let control = this.getControl(key);
if (control) {
return control.value;
}
return null;
}
public getInitialValue(key: string): any {
let control = this.getControl(key);
if (control) {
return control.initialValue;
}
return null;
}
public setValue(key: string, value: any, options?: {
onlySelf?: boolean,
emitEvent?: boolean,
emitModelToViewChange?: boolean,
emitViewToModelChange?: boolean
}): void {
let control = this.getControl(key);
if (control) {
control.setValue(value, options);
}
}
public patchValue(key: string, value: any, options?: {
onlySelf?: boolean,
emitEvent?: boolean,
emitModelToViewChange?: boolean,
emitViewToModelChange?: boolean
}): void {
let control = this.getControl(key);
if (control) {
control.setValue(value, options);
}
}
public setReadOnly(key: string, isReadOnly: boolean): void {
let control = this.getControl(key);
if (control) {
control.setReadOnly(isReadOnly);
}
}
public setRequired(key: string, required: boolean): void {
let control = this.getControl(key);
if (control) {
control.setRequired(required);
}
}
public hide(key: string, clearValue: boolean = true): void {
let control = this.getControl(key);
if (control) {
control.hide(clearValue);
this.disable(key, { emitEvent: false });
}
}
public show(key: string): void {
let control = this.getControl(key);
if (control) {
control.show();
this.enable(key, { emitEvent: false });
}
}
public disable(key: string, options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}): void {
let control = this.getControl(key);
if (control) {
control.disable(options);
}
}
public enable(key: string, options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}): void {
let control = this.getControl(key);
if (control) {
control.enable(options);
}
}
public markAsInvalid(key: string, validationMessage?: string): void {
let control = this.getControl(key);
if (control) {
if (control) {
control.markAsInvalid(validationMessage);
}
}
}
public markAsDirty(key: string, options?: {
onlySelf?: boolean;
}): void {
let control = this.getControl(key);
if (control) {
control.markAsDirty(options);
}
}
public markAsPending(key: string, options?: {
onlySelf?: boolean;
}): void {
let control = this.getControl(key);
if (control) {
control.markAsPending(options);
}
}
public markAsPristine(key: string, options?: {
onlySelf?: boolean;
}): void {
let control = this.getControl(key);
if (control) {
control.markAsPristine(options);
}
}
public markAsTouched(key: string, options?: {
onlySelf?: boolean;
}): void {
let control = this.getControl(key);
if (control) {
control.markAsTouched(options);
}
}
public markAsUntouched(key: string, options?: {
onlySelf?: boolean;
}): void {
let control = this.getControl(key);
if (control) {
control.markAsUntouched(options);
}
}
public updateValueAndValidity(key: string, options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}): void {
let control = this.getControl(key);
if (control) {
control.updateValueAndValidity(options);
}
}
public displayToast(toastConfig: {
message: string,
title?: string,
hideDelay?: number,
icon?: string,
theme?: string,
position?: string,
isCloseable?: boolean,
customClass?: string
}): void {
if (this.toaster) {
this.toaster.alert(toastConfig);
}
}
public displayTip(key: string, tip: string, icon?: string, allowDismiss?: boolean): void {
let control = this.getControl(key);
if (control) {
control.tipWell = {
tip: tip,
icon: icon,
button: allowDismiss
};
}
}
public confirmChanges(key: string, message?: string): Promise<boolean> {
let history = this.getProperty(key, 'valueHistory');
let oldValue = history[history.length - 2];
let newValue = this.getValue(key);
let label = this.getProperty(key, 'label');
return this.modalService.open(ControlConfirmModal, { oldValue, newValue, label, message, key }).onClosed.then(result => {
if (!result) {
this.setValue(key, oldValue, { emitEvent: false });
}
});
}
public setProperty(key: string, prop: string, value: any): void {
let control = this.getControl(key);
if (control) {
control[prop] = value;
}
}
public getProperty(key: string, prop: string): any {
let control = this.getControl(key);
if (control) {
return control[prop];
}
return null;
}
public isValueEmpty(key: string): boolean {
let value = this.getValue(key);
return Helpers.isEmpty(value);
}
public isValueBlank(key: string): boolean {
let value = this.getValue(key);
return Helpers.isBlank(value);
}
public hasField(key: string): boolean {
return !!this.form.controls[key];
}
public addStaticOption(key: string, newOption: any): void {
let control = this.getControl(key);
let optionToAdd = newOption;
if (control) {
let currentOptions = this.getProperty(key, 'options');
if (!currentOptions || !currentOptions.length) {
let config = this.getProperty(key, 'config');
if (config) {
currentOptions = config.options;
if (currentOptions && Array.isArray(currentOptions)) {
if (currentOptions[0].value && !optionToAdd.value) {
optionToAdd = { value: newOption, label: newOption };
}
config.options = [...currentOptions, optionToAdd];
this.setProperty(key, 'config', config);
}
}
} else {
if (currentOptions[0].value && !optionToAdd.value) {
optionToAdd = { value: newOption, label: newOption };
}
this.setProperty(key, 'options', [...currentOptions, optionToAdd]);
}
}
}
public removeStaticOption(key: string, optionToRemove: string): void {
let control = this.getControl(key);
if (control) {
let currentOptions = this.getProperty(key, 'options');
if (!currentOptions || !currentOptions.length) {
let config = this.getProperty(key, 'config');
if (config) {
currentOptions = config.options;
if (currentOptions && Array.isArray(currentOptions)) {
let index = -1;
currentOptions.forEach((opt, i) => {
if (opt.value || opt.label) {
if (opt.value === optionToRemove || opt.label === optionToRemove) {
index = i;
}
} else {
if (opt === optionToRemove) {
index = i;
}
}
});
if (index !== -1) {
currentOptions.splice(index, 1);
}
config.options = [...currentOptions];
this.setProperty(key, 'config', config);
}
}
} else {
let index = -1;
currentOptions.forEach((opt, i) => {
if (opt.value || opt.label) {
if (opt.value === optionToRemove || opt.label === optionToRemove) {
index = i;
}
} else {
if (opt === optionToRemove) {
index = i;
}
}
});
if (index !== -1) {
currentOptions.splice(index, 1);
}
this.setProperty(key, 'options', [...currentOptions]);
}
}
}
public modifyPickerConfig(key: string, config: { format?: string, optionsUrl?: string, optionsUrlBuilder?: Function, optionsPromise?: any, options?: any[] }, mapper?: Function): void {
let control = this.getControl(key);
if (control) {
let newConfig: any = Object.assign({}, control.config);
if (config.optionsUrl || config.optionsUrlBuilder || config.optionsPromise) {
newConfig = {
format: config.format,
options: (query) => {
if (config.optionsPromise) {
return config.optionsPromise(query, this.http);
}
return new Promise((resolve, reject) => {
let url = config.optionsUrlBuilder ? config.optionsUrlBuilder(query) : `${config.optionsUrl}?filter=${query || ''}`;
if (query && query.length) {
this.http
.get(url)
.map(res => {
if (res.json) {
return res.json();
}
return res;
})
.map(results => {
if (mapper) {
return results.map(mapper);
}
return results;
})
.subscribe(resolve, reject);
} else {
resolve([]);
}
});
}
};
} else if (config.options) {
newConfig.options = [...config.options];
}
this.setProperty(key, 'config', newConfig);
}
}
public setLoading(key: string, loading: boolean) {
let control = this.getControl(key);
if (control) {
if (loading) {
this.form.controls[key].fieldInteractionloading = true;
control.setErrors({ 'loading': true });
// History
clearTimeout(this.asyncBlockTimeout);
this.asyncBlockTimeout = setTimeout(() => {
this.setLoading(key, false);
this.displayTip(key, this.labels.asyncFailure, 'info', false);
this.setProperty(key, '_displayedAsyncFailure', true);
}, 10000);
} else {
this.form.controls[key].fieldInteractionloading = false;
clearTimeout(this.asyncBlockTimeout);
control.setErrors({ 'loading': null });
control.updateValueAndValidity({ emitEvent: false });
if (this.getProperty(key, '_displayedAsyncFailure')) {
this.setProperty(key, 'tipWell', null);
}
}
}
}
public addControl(key: string, metaForNewField: any, position: string = FieldInteractionApi.FIELD_POSITIONS.ABOVE_FIELD, initialValue?: any): void {
if (!metaForNewField.key && !metaForNewField.name) {
console.error('[FieldInteractionAPI] - missing "key" in meta for new field'); // tslint:disable-line
return null;
}
if (!metaForNewField.key) {
// If key is not explicitly declared, use name as key
metaForNewField.key = metaForNewField.name;
}
if (this.form.controls[metaForNewField.key]) {
// Field is already on the form
return null;
}
let control = this.form.controls[key];
let fieldsetIndex, controlIndex;
if (control) {
fieldsetIndex = -1;
controlIndex = -1;
this.form.fieldsets.forEach((fieldset, fi) => {
fieldset.controls.forEach((fieldsetControl, ci) => {
if (fieldsetControl.key === key) {
fieldsetIndex = fi;
controlIndex = ci;
}
});
});
// Change the position of the newly added field
switch (position) {
case FieldInteractionApi.FIELD_POSITIONS.ABOVE_FIELD:
// Adding field above active field
// index can stay the same
break;
case FieldInteractionApi.FIELD_POSITIONS.BELOW_FIELD:
// Adding field below active field
controlIndex += 1;
break;
case FieldInteractionApi.FIELD_POSITIONS.TOP_OF_FORM:
// Adding field to the top of the form
controlIndex = 0;
fieldsetIndex = 0;
break;
case FieldInteractionApi.FIELD_POSITIONS.BOTTOM_OF_FORM:
// Adding field to the bottom of the form
fieldsetIndex = this.form.fieldsets.length - 1;
controlIndex = this.form.fieldsets[fieldsetIndex].controls.length;
break;
default:
break;
}
if (fieldsetIndex !== -1 && controlIndex !== -1) {
let novoControl = this.formUtils.getControlForField(metaForNewField, this.http, {});
novoControl.hidden = false;
let formControl = new NovoFormControl(initialValue, novoControl);
this.form.addControl(novoControl.key, formControl);
this.form.fieldsets[fieldsetIndex].controls.splice(controlIndex, 0, novoControl);
}
}
}
public removeControl(key: string): void {
if (!this.form.controls[key]) {
// Field is not on the form
return null;
}
let control = this.getControl(key);
if (control) {
let fieldsetIndex = -1;
let controlIndex = -1;
this.form.fieldsets.forEach((fieldset, fi) => {
fieldset.controls.forEach((fieldsetControl, ci) => {
if (fieldsetControl.key === key) {
fieldsetIndex = fi;
controlIndex = ci;
}
});
});
if (fieldsetIndex !== -1 && controlIndex !== -1) {
this.form.removeControl(key);
this.form.fieldsets[fieldsetIndex].controls.splice(controlIndex, 1);
}
}
}
}