mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
3.6 KiB
148 lines
3.6 KiB
/*
|
|
* Squidex Headless CMS
|
|
*
|
|
* @license
|
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
|
|
*/
|
|
|
|
import { AbstractControl, ValidatorFn } from '@angular/forms';
|
|
import { ErrorDto, Types } from '@app/framework/internal';
|
|
import { State } from './../../state';
|
|
import { ErrorValidator } from './error-validator';
|
|
import { addValidator, getRawValue, hasNonCustomError, updateAll } from './forms-helper';
|
|
|
|
export interface FormState {
|
|
// The number of submits.
|
|
submitCount: number;
|
|
|
|
// True, when the submitting is in progress.
|
|
submitting: boolean;
|
|
|
|
// The current remote error.
|
|
error?: ErrorDto | null;
|
|
}
|
|
|
|
export class Form<T extends AbstractControl, TOut, TIn = TOut> {
|
|
private readonly state = new State<FormState>({ submitCount: 0, submitting: false });
|
|
private readonly errorValidator = new ErrorValidator();
|
|
|
|
public submitCount =
|
|
this.state.project(s => s.submitCount);
|
|
|
|
public submitted =
|
|
this.state.project(s => s.submitCount > 0);
|
|
|
|
public submitting =
|
|
this.state.project(s => s.submitting);
|
|
|
|
public error =
|
|
this.state.project(s => s.error);
|
|
|
|
public get remoteValidator(): ValidatorFn {
|
|
return this.errorValidator.validator;
|
|
}
|
|
|
|
constructor(
|
|
public readonly form: T,
|
|
) {
|
|
addValidator(form, this.errorValidator.validator);
|
|
}
|
|
|
|
public setEnabled(isEnabled: boolean) {
|
|
if (isEnabled) {
|
|
this.enable();
|
|
} else {
|
|
this.disable();
|
|
}
|
|
}
|
|
|
|
protected enable() {
|
|
this.form.enable();
|
|
}
|
|
|
|
protected disable() {
|
|
this.form.disable();
|
|
}
|
|
|
|
protected setValue(value?: Partial<TIn>) {
|
|
if (value) {
|
|
this.form.reset(this.transformLoad(value));
|
|
} else {
|
|
this.form.reset();
|
|
}
|
|
}
|
|
|
|
protected transformLoad(value: Partial<TIn>): any {
|
|
return value;
|
|
}
|
|
|
|
protected transformSubmit(value: any): TOut {
|
|
return value;
|
|
}
|
|
|
|
public load(value: Partial<TIn> | undefined) {
|
|
this.state.resetState();
|
|
|
|
this.setValue(value);
|
|
}
|
|
|
|
public submit(): TOut | null {
|
|
this.updateSubmitState(null, true);
|
|
|
|
this.form.markAllAsTouched();
|
|
|
|
if (!hasNonCustomError(this.form)) {
|
|
const value = this.transformSubmit(getRawValue(this.form));
|
|
|
|
if (value) {
|
|
this.disable();
|
|
}
|
|
|
|
return value;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public submitCompleted(options?: { newValue?: TOut; noReset?: boolean }) {
|
|
this.updateSubmitState(null, false);
|
|
|
|
this.enable();
|
|
|
|
if (options && options.noReset) {
|
|
this.form.markAsPristine();
|
|
} else {
|
|
this.setValue(options?.newValue);
|
|
}
|
|
}
|
|
|
|
public submitFailed(errorOrMessage?: string | ErrorDto, replaceDetails = true) {
|
|
this.updateSubmitState(errorOrMessage, false, replaceDetails);
|
|
|
|
this.enable();
|
|
}
|
|
|
|
private updateSubmitState(errorOrMessage: string | ErrorDto | undefined | null, submitting: boolean, replaceDetails = true) {
|
|
const error = getError(errorOrMessage);
|
|
|
|
this.state.next(s => ({
|
|
submitCount: s.submitCount + (submitting ? 1 : 0),
|
|
submitting,
|
|
error,
|
|
}));
|
|
|
|
if (replaceDetails) {
|
|
this.errorValidator.setError(error);
|
|
|
|
updateAll(this.form);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getError(error?: string | ErrorDto | null): ErrorDto | undefined | null {
|
|
if (Types.isString(error)) {
|
|
return new ErrorDto(500, error);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|