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
ReactiveVar
for fields with dynamic state, such as editors or file uploaders. - Define form sections using
components-composite-title
to 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
params
object.