import { customElement, bindable, inject, InlineViewStrategy } from 'aurelia-framework';
import { Guid } from '../../resources/guid';
import { SchemaFormLogger } from '../../resources/logger';
import { IFormOverride } from '../../interfaces/form-override';
import { FormService } from '../../services/form-service';
import { ValidateResult } from 'aurelia-validation';
import { ArrayRules } from '../../rules/array-rules';
import { DefaultsService } from '../../services/defaults-service';
import { FormInstances } from '../../services/form-instances';
import { IFormInstance } from '../../interfaces/form-instance';
import * as $ from 'jquery';
@inject(
ArrayRules,
FormService,
SchemaFormLogger,
DefaultsService,
FormInstances
)
@customElement('sf-array')
export class SfArray {
@bindable form: IFormOverride;
@bindable model: any[];
@bindable formInstance: string;
id: string = Guid.newGuid();
kind = 'array';
viewStrategy: string;
itemViewStrategy: InlineViewStrategy;
tabTitleTemplate: InlineViewStrategy;
validationErrors: string[];
errors: ValidateResult[];
bound: boolean = false;
private formCtrl: IFormInstance;
constructor(
public arrayRules: ArrayRules,
private formService: FormService,
private logger: SchemaFormLogger,
private defaultsService: DefaultsService,
private formInstances: FormInstances
) { }
async bind() {
if (!this.bound) {
this.logger.info('sf-array', { form: this.form, model: this.model });
this.formCtrl = this.formInstances.get(this.formInstance);
this.bindRules();
this.form.$arrayItem.$schema = this.form.$schema.items;
await this.createItemView();
await this.determineViewStrategy();
await this.initializeArray();
this.bound = true;
}
}
unbind() {
this.unbindRules();
}
async initializeArray() {
if (
this.form.$arrayItem.$schema.enum ||
(this.model && this.model.length > 0) ||
this.form.$noEmptyArrayInitialization ||
this.formCtrl.formOptions.noEmptyArrayInitialization
) {
return;
}
await this.add(!!this.formCtrl.formOptions.validateOnRender);
}
attached() {
this.logger.info('sf-array-attached');
if (this.formCtrl.formOptions.validateOnRender) {
this.validate();
}
}
async determineViewStrategy() {
let strategy;
if (this.form.$altTemplate) {
strategy = this.form.$altTemplate;
} else if (this.form.$arrayAsTabs) {
const content = !!this.form.$tabTitle ? `${this.form.$tabTitle}` : '${\'Item \' + ($index + 1)}';
this.tabTitleTemplate = new InlineViewStrategy(`${content}`);
strategy = this.formService.getTemplatePath('arrayTabs');
} else if (this.form.$schema.items.type === 'string' && this.form.$schema.items.enum) {
strategy = this.formService.getTemplatePath('arrayStringEnum');
} else {
strategy = this.formService.getTemplatePath('array');
}
this.viewStrategy = strategy;
}
async createItemView() {
this.logger.info('createView', { form: this.form.$arrayItem });
const template = this.formService
.getSfTemplate(
'model[$index]',
'form.$arrayItem',
this.form.$arrayItem.$schema.type,
this.formInstance
);
this.logger.info('createView-template', { template });
this.itemViewStrategy = new InlineViewStrategy(`${template}`);
}
private bindRules() {
this.arrayRules.bind(this);
this.formCtrl.validationController.addObject(this.model);
}
unbindRules() {
this.formCtrl.validationController.removeObject(this.model);
}
async add(validate: boolean) {
if (!this.isDisabled && !this.atCapacity) {
const item = await this.defaultsService.getSchemaDefaultAsync(this.form.$schema.items, null);
this.unbindRules();
const index = this.model.push(item) - 1;
this.bindRules();
this.selectTab(index);
if (validate) {
await this.validate();
}
}
}
async remove(index: number, validate: boolean) {
this.unbindRules();
this.model.splice(index, 1);
this.bindRules();
this.selectTab(this.model.length - 1);
if (validate) {
await this.validate();
}
}
private selectTab(index: number) {
if (this.tabTitleTemplate) {
setTimeout(() => {
$(`a[href="#tab_${this.id}_${index}"]`).tab('show');
}, 50);
}
}
get isDisabled(): boolean {
return this.form.$schema.readOnly || !!this.form.$schema.const;
}
get atCapacity(): boolean {
return Number.isInteger(this.form.$schema.maxItems)
? this.model.length >= this.form.$schema.maxItems : false;
}
async validate() {
const result = await this.formCtrl.validationController.validate({ object: this.model });
this.logger.info('validated array', result);
this.errors = result.results
.filter((r) => !r.valid);
return result;
}
}