Nested form issue - TypeError: Cannot read properties of undefined (reading '0')

Hello, I am new in Vaadin. I tried to follow Binding arrays tutorial, but something it does not work.

I trying to use it for simple invoicing application (one invoice can have multiple invoice rows)

I use Vaadin version 24.6.0. Java 23, Lombok.

The react component looks like this:

import {useForm, useFormArrayPart, useFormPart} from '@vaadin/hilla-react-form';
import TransactionModel from 'Frontend/generated/com/example/application/entity/TransactionModel';
import InvoiceItemModel from 'Frontend/generated/com/example/application/entity/InvoiceItemModel';
import {Button, NumberField, TextField} from "@vaadin/react-components";


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

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

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

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

When I click on the “Add button”, then I get following error: TypeError: Cannot read properties of undefined (reading '0') at _BinderNode.initializeValue (.

The java entity looks like this

@Entity
@Table(name = "transactions")
...
public class Transaction {

...

  @OneToMany(mappedBy = "transaction", cascade = CascadeType.ALL)
  private List<InvoiceItem> items = new ArrayList<>();

}

@Entity
@Table(name = "invoice_items")
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Getter
@Setter
public class InvoiceItem {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long itemId;

  @ManyToOne
  @JoinColumn(name = "transaction_id", nullable = false)
  private Transaction transaction;

  @NotNull
  @Min(1)
  private Integer quantity;

}


I have also tried many modifications.
Could you help with root cause analysis of the provided code?
Thank you for your help.

In fact, that examples related to binding arrays are now working.
I usually do initialization before binding. There is no official docs about this behavier.
Try something like this

useEffect(()=>{
 const initialValue = TransactionModel.createEmptyValue();
 initialValue.items = []; // here you make array [] instead of undefined
 read(initialValue); // read() is accessible from const { field, model, read } = useForm(TransactionModel);
},[]);

Another workaround is to mark items as @NotNull in Java class, but it depends on your buisness logic.

1 Like

Thank you very much. It works!

Opened Cannot add items to nullable array · Issue #3102 · vaadin/hilla · GitHub as the workaround shouldn’t be necessary.