Search code examples
reactjsmany-to-manyantdrefine.js

Ant design multiple select for nested objects


I'm building a dashboard using refine.dev and AntDesign.

One of my entities has Many-to-Many relation that is returned in the API as an array of objects with id properties.

{
  "id": 1,
  "relations": [
    {
      "id": 1
    },
    {
      "id": 2
    }
  ]
}

I need to build a form with a “multiple select” component. And I follow this tutorial. But unfortunately, it has examples only for “many-to-one” relations.

First I generate selectProps. This part goes all right.

const { selectProps: relationsSelectProps } = useSelect<Relation>({
  resource: 'relations',
  optionLabel: 'name',
  defaultValue: record?.relations.map((r) => r.id),
});

Then starts the problem. When I'm trying to create a form item

<Form.Item
  name={['relations']}
>
  <Select
    mode="multiple"
    {...relationsSelectProps}
  />
</Form.Item>

I can't make it work with multiple nested objects.

I tried different name paths: ['relations', 'id'], and ['relations', '*', 'id']

Tried to play around with the normalize property.

I don't really want to flatten these objects on the backend side, so the question is: what's the best practice to make this work on the react side of the project?


Solution

  • So you can do this thing by adding two properties to the Form.Item component.

    1. getValueFromEvent to transform Select's values to form
    2. getValueProps to do it the other way around
    <Form.Item
      name={['relations']}
      getValueFromEvent={(values) => {
        return values.map((id: number) => ({ id }));
      }}
      getValueProps={(ids) => {
        return ids?.map(({ id }: { id: number }) => id);
      }}
    >
      <Select
        mode="multiple"
        {...selectProps}
      />
    </Form.Item>
    

    Then the post (patch) request's gonna look the right way:

    {
      "relations": [
        { "id": 1 },
        { "id": 2 }
      ],
      // other fields
    }