Field array
Initialization
Section titled “Initialization”There are several ways to initialize array fields:
Simple Array Literals
Section titled “Simple Array Literals”const form = reatomForm({ // Empty array field tags: [],
// Array with default item as a string field emails: ['default@example.com'],
// Array with default item as a string field through options definition phones: [ { initState: '123-456-7890', validateOnChange: true } ]}, 'form')Empty Array with Type Information
Section titled “Empty Array with Type Information”const form = reatomForm({ // Empty array with correct type information emails: new Array<string>(), contacts: new Array<{ name: string, phone: string }>()}, 'form')Complex Array Field Factory
Section titled “Complex Array Field Factory”If you want to configure the rules for creating fields in an array field, you should define a factory function using experimental_fieldArray function that describes how each new field in this array field will be created.
const form = reatomForm({ // Using initState and create phoneNumbers: experimental_fieldArray({ initState: [{ number: '123-456-7890', priority: false }], create: ({ number, priority }, name) => ({ number: { initState: number, validateOnChange: true }, priority: reatomBoolean(priority, `${name}.priority`).pipe(withField()) }) }),}, 'form')
form.fields.phoneNumbers.create({ number: '123-456-7890', priority: false})Basic Array Field Operations
Section titled “Basic Array Field Operations”Since field array or array literal in the fields definition are a syntactic sugar over reatomLinkedList, it provides several methods to manipulate the array of fields:
create(value): Adds a new field with the given value to the end of the arrayremove(field): Removes a specific field from the arrayclear(): Removes all fields from the arrayarray(): Returns an array of all fields, which you should use to iterate over the fieldsswap(field1, field2): Swaps the positions of two fields in the arraymove(field, targetField): Moves a field to a position after the target field (use null to move to the beginning)find(predicate): Finds a field in the array that matches the predicate function
When rendering field arrays in UI components, you should always use the .array() method to iterate over the fields.
import { reatomForm } from '@reatom/core'
const contactForm = reatomForm({ name: '', emails: [''] // Simple array of string fields}, 'form')
// Add a new email fieldcontactForm.fields.emails.create('')
// Access the array of email fieldsconst emailFields = contactForm.fields.emails.array()
// Iterate over the fields to render them// In React, this would look like:// {emailFields.map((emailField) => (// <EmailFieldComponent key={emailField.name} field={emailField} />// ))}
// Remove a specific email fieldcontactForm.fields.emails.remove(emailFields[0])
// Clear all email fieldscontactForm.fields.emails.clear()Since we use the “field as model” approach and each field is an object, we can achieve maximum type safety by working directly with objects. But the cherry on top is atomization, a principle used by array fields that allows maintaining a high-quality type-safe experience at any level of nesting in your forms.
Nested Array Fields
Section titled “Nested Array Fields”You can also create nested array structures:
import { reatomForm } from '@reatom/core'
const userForm = reatomForm({ name: '', addresses: [ { street: '', city: '', tags: ['home'] } ]}, 'form')
// Access nested fieldsconst addresses = userForm.fields.addresses.array()const firstAddressTags = addresses[0]?.tags.array()Also you can use ArrayFieldItem type helper to infer type of the field array item:
import type { ArrayFieldItem } from '@reatom/core'
type AddressFieldType = ArrayFieldItem<typeof form.fields.addresses>;
function AddressField({ model }: { model: AddressFieldType }) { // ...}``