Docs

Documentation versions (currently viewingVaadin 24)

Binding Arrays

Working with arrays using form binding API.

This page explains working with arrays when building TypeScript form views using form binding. Consider a form for a Java bean that has this structure:

/**
 * Example bean with array field
 */
public class Group {
    ...

    public Person[] getPeople() {
        ...
    }

    public void setPeople(Person[] people) {
        ...
    }
}

Repeating the Array Item Template

A common need when working with arrays is to iterate over the items and stamp a template for each item. With form binding, array models are iterable. You can use the useFormArrayPart hook to iterate over the model and to get and set the value of the array.

As you also need to get the field function for each item using the useFormPart hook, you need to create a component for the array item template.

import { useForm, useFormArrayPart, useFormPart } from '@vaadin/hilla-react-form';
import { NumberField, TextField } from '@vaadin/react-components';
import GroupModel from '.../GroupModel';
import PersonModel from '.../PersonModel';

function PersonForm({ model }: { model: PersonModel }) {
    const { field } = useFormPart(model);

    return (
        <div>
            <TextField {...field(model.fullName)} />
            <NumberField {...field(model.age)} />
        </div>
    );
}

export default function GroupFormView() {
    const { field, model } = useForm(GroupModel);
    const { items} = useFormArrayPart(model.people);

    return (
        <>
            <TextField {...field(model.name)} />
            {items.map((person, index) => (
                <PersonForm key={index} model={person} />
            ))}
        </>
    );
}

Adding & Removing Array Items

You can modify the array value by using the value and setValue functions provided by useFormArrayPart.

import { useForm, useFormArrayPart, useFormPart } from '@vaadin/hilla-react-form';
import { Button, NumberField, TextField } from '@vaadin/react-components';
import GroupModel from '.../GroupModel';
import PersonModel from '.../PersonModel';

function PersonForm({ model, remove }: { model: PersonModel, remove: () => void }) {
    const { field } = useFormPart(model);

    return (
        <div>
            <TextField {...field(model.fullName)} />
            <NumberField {...field(model.age)} />
            <Button onClick={remove}>Remove</Button>
        </div>
    );
}

export default function GroupFormView() {
    const { field, model } = useForm(GroupModel);
    const { items, value, setValue } = useFormArrayPart(model.people);

    return (
        <>
            <TextField {...field(model.name)} />
            {items.map((person, index) => (
                <PersonForm key={index} model={person} remove={() => setValue(value!.filter((_, i) => i !== index))} />
            ))}
            <Button onClick={() => setValue([...(value ?? []), PersonModel.createEmptyValue()])}>Add person</Button>
        </>
    );
}