---
# System prepended metadata

title: Data object and array
tags: [zeta-dom-react]

---

---
tags: zeta-dom-react
---

# Data object and array

==Since `v0.4.0`==

Nested data objects and arrays are supported since v0.4.

Field components can be associated with nested data properties using `FormObject` and `FormArray` component.

```typescript
interface FormData {
    name: string;
    phone: {
        countryCode: string;
        phoneNumber: string;
    };
}

function Form() {
    const form = useFormContext<FormData>();
    return (
        <Form context={form}>
            <TextField name="name" />
            <FormObject name="phone">
                <TextField name="countryCode" />
                <TextField name="phoneNumber" />
            </FormObject>
        </Form>
    );
}
```

## Field component for data objects

```typescript
interface PhoneData {
    countryCode: string;
    phoneNumber: string;
}

function PhoneField(props: FormFieldProps<PhoneData>) {
    const { value } = useFormField(props, {});
    return (
        <div>
            <FormObject value={value}>
                <TextField name="countryCode" />
                <TextField name="phoneNumber" />
            </FormObject>
        </div>
    );
}

function Form() {
    const form = useFormContext<FormData>();
    return (
        <Form context={form}>
            <TextField name="name" />
            <PhoneField name="phone" />
        </Form>
    );
}
```

## Data array

```typescript
interface Item {
    id: string;
    name: string;
}

interface FormData {
    items: Item[];
}

function Form() {
    const form = useFormContext<FormData>();
    return (
        <Form context={form}>
            <FormArray name="items">
                {items => item.map(v => (
                    // important to provide key for each mapped element
                    <FormObject key={FormObject.keyFor(v)} value={v}>
                        <div>
                            <TextField name="id" />
                            <TextField name="name" />
                        </div>
                    </FormObject>
                ))}
            </FormArray>
        </Form>
    );
}
```

Or by having a composite field component simply:

```typescript
function Form() {
    const form = useFormContext<FormData>();
    return (
        <Form context={form}>
            <FormArray name="items">
                {items => item.map((v, i) => (
                    <Field key={FormObject.keyFor(v)} name={i} />
                ))}
            </FormArray>
        </Form>
    );
}
```

## Data path

Events and operation like validations on nested data properties can be achieved like normal data properties with dot-separated data paths.

```typescript
function Form() {
    const form = useFormContext<FormData>();
    useEffect(() => {
        return form.on('dataChange', function (e) {
            console.log(e.data);
        });
    }, [form]);
    return (
        <Form context={form}>
            <TextField name="name" />
            <FormObject name="phone">
                <TextField name="countryCode" />
                <TextField name="phoneNumber" />
            </FormObject>
        </Form>
    );
}
```

For instance, the above `dataChange` event handler will log `["phone.countryCode"]` when user fills in the country code.

### Validate nested properties

To validate a particular data property, provide the data path to that property like:

```typescript
form.validate('phone.countryCode')
```

You can also supply the root object data path to validate all child properties:


```typescript
form.validate('phone')
// same as 
form.validate('phone.countryCode', 'phone.phoneNumber')
```

### Access data with data path

Other than accessing like ordinary JavaScript objects, `FormContext` provides `getValue` and `setValue` method to access values providing a data path.

```typescript
const countryCode = form.getValue('phone.countryCode');
form.setValue('phone.countryCode', '1');
```
:::warning
Note that for data objects and array, `getValue` will return a deeply-cloned object; while `setValue` will deeply clone the supplied object.
:::