Source code
src/showcase/pages/forms.js
This file is included in this documentation build. It is displayed as code and is not executed.
/**
* Demo jobs, notification, preferences, and form workflows.
*
* @author Laurent Declercq l.declercq@agon-innovation.ch
* @version 20260921
*/
import { controlDemo } from './controls.js';
/**
* Create an accessible sample form with explicit validation and busy state.
*
* @param {object} services - Resource creation adapter.
* @returns {object} Alpine provider.
*/
export function projectForm(services) {
return {
/** @type {object} Draft fields, never interpreted as HTML. */
form: { name: '', email: '', notes: '', type: 'application', confirmed: false },
/**
* Whether field validation needs an announced summary.
*
* @returns {boolean} Validation state.
*/
get hasErrors() {
return Object.keys(this.errors).length > 0;
},
/** @type {Record<string,string>} Field validation messages. */
errors: {},
/** @type {boolean} Prevent duplicate submissions. */
saving: false,
/**
* Validate and create a sample project in the resource list.
*
* @returns {Promise<void>}
*/
async submit() {
if (this.saving) {
return;
}
this.errors = {};
if (!this.form.name.trim()) {
this.errors.name = this.$t('required');
}
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.form.email)) {
this.errors.email = this.$t('invalidEmail');
}
if (!this.form.confirmed) {
this.errors.confirmed = this.$t('required');
}
if (Object.keys(this.errors).length) {
this.$nextTick(
/**
* Focus the first invalid project field after validation renders.
*
* @returns {void}
*/
() => this.$el.querySelector('[aria-invalid="true"]')?.focus()
);
return;
}
this.saving = true;
try {
await services.save('resources', {
name: this.form.name.trim(),
notes: this.form.notes,
type: this.form.type,
status: 'active',
region: 'Zurich'
});
this.$store.toasts.push(this.$t('projectCreated'));
this.form = { name: '', email: '', notes: '', type: 'application', confirmed: false };
} finally {
this.saving = false;
}
}
};
}
/**
* Register the forms page provider after its route module is requested.
*
* @param {object} context - Application runtime and consumer-owned services.
* @param {object} context.Alpine - Active Alpine runtime.
* @param {object} context.services - Consumer-owned services.
* @returns {void} Makes the page controller available before template mounting.
*/
export function register({ Alpine, services }) {
Alpine.data('controlDemo', controlDemo);
Alpine.data(
'projectForm',
/**
* Construct a fresh forms controller for the mounted page.
*
* @returns {object} New page provider with its own lifecycle state.
*/
() => projectForm(services)
);
}