Move JSON Schema logic to Declaform instead of making another component.
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
import Ajv, { type ValidateFunction } from 'ajv';
|
||||
import addFormats from 'ajv-formats';
|
||||
|
||||
const ajv = new Ajv({
|
||||
coerceTypes: true,
|
||||
});
|
||||
addFormats(ajv);
|
||||
|
||||
interface FieldElement {
|
||||
name: string;
|
||||
type: string;
|
||||
@@ -93,13 +101,17 @@ export class Declaform extends HTMLElement {
|
||||
'src', // defines api endpoint used to hydrate this object
|
||||
'action', // defines api endpoint used to submit this object to
|
||||
'method', // defines http method to use on "action" endpoint
|
||||
]
|
||||
'schema', // url for a remote JSON Schema definition
|
||||
];
|
||||
|
||||
/* The character that gets used to join multiple field values */
|
||||
static joining_char = ',';
|
||||
|
||||
private _fields: Field[];
|
||||
private _form: HTMLFormElement | null;
|
||||
private _validate: ValidateFunction | undefined;
|
||||
ready: Promise<void>;
|
||||
private readyResolve!: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -109,6 +121,10 @@ export class Declaform extends HTMLElement {
|
||||
this.shadowRoot!.innerHTML = '<slot name="form"></slot>';
|
||||
this._fields = [];
|
||||
this._form = null;
|
||||
this._validate = undefined;
|
||||
this.ready = new Promise(resolve => {
|
||||
this.readyResolve = resolve;
|
||||
})
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
@@ -151,10 +167,23 @@ export class Declaform extends HTMLElement {
|
||||
this.hydrateFromEndpoint(src);
|
||||
}
|
||||
|
||||
const schemaUrl = this.getAttribute('schema');
|
||||
if (schemaUrl) {
|
||||
const res = await fetch(schemaUrl);
|
||||
const schema = await res.json();
|
||||
this._validate = ajv.compile(schema);
|
||||
}
|
||||
|
||||
this._form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
await this.submit();
|
||||
})
|
||||
const isValid = (this.hasAttribute('schema')) ?
|
||||
await this.validate(e) : true;
|
||||
if (isValid) {
|
||||
await this.submit();
|
||||
}
|
||||
});
|
||||
|
||||
this.readyResolve();
|
||||
}
|
||||
|
||||
get form() {
|
||||
@@ -202,13 +231,24 @@ export class Declaform extends HTMLElement {
|
||||
populateFields(obj, '');
|
||||
}
|
||||
|
||||
async validate(e?: SubmitEvent) {
|
||||
e?.preventDefault();
|
||||
if (!this._validate) {
|
||||
console.warn(`[Declaform] Warning: _validate is not defined`)
|
||||
return true;
|
||||
}
|
||||
const obj = this.toObject();
|
||||
const isValid = this._validate(obj);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
private async hydrateFromEndpoint(endpoint: string): Promise<void> {
|
||||
const response = await fetch(endpoint);
|
||||
const obj = await response.json();
|
||||
this.hydrate(obj);
|
||||
}
|
||||
|
||||
private async submit(): Promise<void> {
|
||||
async submit(): Promise<void> {
|
||||
const method = this.getAttribute('method') ?? 'POST';
|
||||
const endpoint = new URL(this.getAttribute('action') ?? '');
|
||||
const obj = this.toObject();
|
||||
|
||||
Reference in New Issue
Block a user