Множественный выбор Ant для вложенных объектов

Я создаю дашборд с помощью Refine.dev и AntDesign.

Один из моих объектов имеет отношение «многие ко многим», которое возвращается в API как массив объектов со свойствами id.

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

Мне нужно создать форму с компонентом «множественный выбор». И я следую этому уроку. Но, к сожалению, в нем есть примеры только для отношений «многие к одному».

Сначала я генерирую selectProps. Эта часть идет нормально.

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

Тогда начинается проблема. Когда я пытаюсь создать элемент формы

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

Я не могу заставить его работать с несколькими вложенными объектами.

Я пробовал разные пути имен: ['relations', 'id'] и ['relations', '*', 'id']

Пытался поиграть со свойством normalize.

Я действительно не хочу сглаживать эти объекты на стороне бэкэнда, поэтому возникает вопрос: как лучше всего заставить это работать на стороне реагирования проекта?

Я не совсем понимаю, чего вы пытаетесь достичь. Можете ли вы привести пример? Обычно Select-Item с mode = "multiple" всегда дает вам отношение one-to-many.

MS1 13.12.2022 18:41

Да. Но это отношение «один ко многим» назначит массив только идентификаторов. Но мне нужно, чтобы он работал с массивом объектов [{"id": 1}, {"id": 2}] и т. д.

Konstantin Bodnia 15.12.2022 12:55
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
2
110
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Итак, первая часть о том, как вы пытаетесь настроить элемент формы в соответствии с вашей моделью.

«Имя» с {[что-то, потомок чего-то]} в Form.Item в основном представляет собой точечную нотацию.

скажем, у меня есть модель, в которой есть отношение, например

  export interface ISubscription {
  id: number;
  sku: string;
  customer: ICustomer
}

и ICustomer выглядит так

    export interface ICustomer {
      id: number;
      name: string;
      surname:: string;
    }

когда вы устанавливаете свой Form.Item, вы можете получить вложенное значение, используя {[]}, например

  <Form.Item
     label = "Customer"
     name = {["customer", "name"]}
     >
      <Input />               
    </Form.Item>

Во-вторых, делать множественный выбор с помощью antd намного сложнее, когда вы выходите за рамки базового варианта использования в Refine.dev.

Я не уверен на 100% в вашем случае использования, но, например, когда мне пришлось сделать множественный выбор с пользовательскими тегами.

<Form.Item label = "Custom Tags">
  <Select
    mode = "multiple"
    value = {customTags}
    onSelect = {handleSelect}
    onDeselect = {handleDeselect}
  >
    {customTagOptions}
  </Select>
</Form.Item>

но вам нужно сделать свои собственные пользовательские параметры, подобные этому

  const customTagOptions = useMemo(() => {
    return tagDataResult?.data
      ?.map(
        // build an array with the id and label for the select option
        (t) => ({ id: t.id, label: `${t.tagType.name} : ${t.name}` })
      )
      .sort(
        // then sort everything
        (a, b) =>
          a.label.localeCompare(b.label, undefined, { sensitivity: "base" })
      )
      .map(
        // then build the final options
        (t) => (
          <Option key = {t.id} value = {t.id} title = {t.label}>
            {t.label}
          </Option>
        )
      );
  }, [tagDataResult?.data]);

потому что да, комбинация antD/refine не позволит вам делать то, что вы хотите из коробки ... вы немного боретесь с фреймворком здесь.

Надеюсь, это немного поможет человеку

Ответ принят как подходящий

Таким образом, вы можете сделать это, добавив два свойства к компоненту Form.Item.

  1. getValueFromEvent для преобразования значений Select в форму
  2. getValueProps сделать наоборот
<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>

Тогда запрос на публикацию (исправление) будет выглядеть правильно:

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

Другие вопросы по теме