open-scd
open-scd copied to clipboard
Form library
As a developer I would like to have a way of quickly creating forms out of a set of input like textfield, checkbox, number input etc. I want to be able to add validators for each form field like required or pattern for a textfield and have the form validate on submit and show errors on its own.
Requirements
- Add wrapper for inputs like textfield, checkbox (what inputs do we need?)
- Implement a handler that can use validator functions on an input and display a custom error message.
- Add common default validators like required, pattern etc
- Trigger validation on form submit
Sketch on how an implementation could look like
type Value = null | string | number | boolean;
// Interface to be usable with material form fields such as MdTextField, MdSelect etc
interface FormField {
value: Value | Value[];
validate: () => boolean;
error: boolean;
errorText: string | null;
}
const dummyField: FormField = {
value: null,
validate: () => true,
error: false,
errorText: null
}
// Return null for a valid field and an error text to display for an validation error
interface Validator {
(fieldValue: Value, formValue: { [key: string]: Value }): null | string;
}
interface FormFieldDefinition {
formField: FormField,
validators?: Validator | Validator[]
}
class FormGroup {
constructor(form: { [key: string]: FormFieldDefinition }) {
}
validate(): boolean {
// Iterate each form field and run its own validate method and every Validator
// Set error and errorText on the form field if necessary
return true;
};
reset(): void {
// Reset error and errorText state on all form fields
}
}
// Have build in Validators for the most common use cases
const Validators = {
Required: (errorMessage: string) => () => errorMessage
}
// ------- Example usage -------
// Form fields are references to MdFormField components
const nameField: FormField = dummyField;
const isActiveField: FormField = dummyField;
const ageField: FormField = dummyField;
// Example for custom validator
const isOver18Validator: Validator = (fieldValue, formValue) => {
if (!fieldValue || typeof fieldValue !== 'number') {
return null;
}
const isValid = fieldValue >= 18
return isValid ? null : 'Age must be 18 or higher';
}
// Define the form group once with appropriate validators attached
const formGroup = new FormGroup({
name: {
formField: nameField,
validators: Validators.Required('Name is required')
},
age: {
formField: ageField,
validators: isOver18Validator
},
isActive: {
formField: isActiveField
}
})
// The form validation should be very easy and short to use
const saveChanges = () => {
if (!formGroup.validate()) {
return;
}
// Save changes etc
}