Form
The Form component in GridStudio enables developers to build rich, reactive forms using a wide variety of atomic and composite UI elements. It supports built-in input validation, file uploads, dynamic dropdowns, AJAX-based option loading, and custom submission logic.
Each form is defined using a sdk.options.items structure, where each item corresponds to a form element. You can group items using arrays to create multi-column layouts and use ReactiveVar bindings to connect external state or editors.
The form also supports lifecycle event handlers, such as onSubmit, enabling full control over data collection, validation, transformation, and submission.
Usage Example
CustomFunction(async function ({ sdk }, reject, resolve) {
resolve(async function CustomFunction({ sdk, templateInstance }) {
const current = sdk.env.current.get()
const coverPhotoDropzone = new ReactiveVar()
const photosDropzone = new ReactiveVar()
const descriptionEditor = new ReactiveVar()
const selectCurrencyOptions = new ReactiveVar([])
sdk.utils.loading.show()
selectCurrencyOptions.set(
current.currencies.map((currency) => ({
value: currency.isoCode,
label: currency.isoCode,
selected: currency.isDefault,
}))
)
sdk.options = {
data: null,
items: [
{
type: 'atoms-input',
name: 'title',
text: 'Title',
rules: { required: true },
},
{
type: 'atoms-editor',
name: 'description',
text: 'Description',
editor: descriptionEditor,
rules: { required: true },
},
[
{
type: 'atoms-dropzone',
name: 'coverPhotoDropzone',
text: 'Cover Photo',
dropzone: coverPhotoDropzone,
options: { acceptedFiles: 'image/*', maxFiles: 1 },
},
{
type: 'atoms-dropzone',
name: 'photosDropzone',
text: 'Photos',
dropzone: photosDropzone,
options: { acceptedFiles: 'image/*', maxFiles: 50 },
},
],
{
type: 'atoms-select',
name: 'currencyIsoCode',
text: 'Currency',
selectOptions: selectCurrencyOptions,
rules: { required: true },
},
{
type: 'atoms-button',
text: 'Create Property',
buttonType: 'submit',
},
],
events: {
onSubmit: async function (event, templateInstance) {
event.preventDefault()
sdk.utils.loading.show()
const title = event.target.title.value
const description = descriptionEditor.get().getData()
const currencyIsoCode = event.target.currencyIsoCode.value
const obj = { title, description, currencyIsoCode }
const coverPhotoUploads = await sdk.utils.uploadAsync(coverPhotoDropzone)
obj.coverPhotoUrl = coverPhotoUploads?.[0]?.url
const photosUploads = await sdk.utils.uploadAsync(photosDropzone)
obj.photosUrls = photosUploads.map((f) => f.url)
await sdk.customFunction.callAsync(
{ pathString: sdk.utils.absolutePathString('../../methods/properties/create.js') },
obj
)
event.target.reset()
sdk.utils.loading.remove()
sdk.utils.drawer.hide()
},
},
}
sdk.utils.loading.remove()
})
})
Key Concepts
| Feature | Description |
|---|---|
items | An array of form elements (or arrays of elements for grouped layout) |
rules | Field-level validation rules such as required |
ReactiveVar | Reactive variables for managing dynamic field states or bindings |
atoms-* types | Atomic UI components like input, select, dropzone, editor, etc. |
components-* types | Composite or layout components (e.g., title separators) |
select-ajax | Dynamically populated dropdowns with search and pagination |
onSubmit | Handler for form submission logic, executed when submit button is clicked |
sdk.utils.uploadAsync | Handles file uploads and returns URLs |
Best Practices
- Use
ReactiveVarfor fields with dynamic state, such as editors or file uploaders. - Define form sections using
components-composite-titleto group related fields. - Use
sdk.utils.loading.show()andsdk.utils.loading.remove()to provide feedback during async actions. - For AJAX selects, handle pagination and filtering manually using the
paramsobject.