Условное отображение массивов объектов в Javascript

У меня есть массив объектов с многоуровневой вложенностью.

const switches = [{
  orgId: "1111a7cd-0d58-11ef-83a2-06a19a0b1f5d",
  orgName: "Management 1",
  orgType: 2,
  organisations: [],
  features: [{
    name: "AdvancedAdminApprovalLevels",
    type: "feature",
    category: "Management Features",
    value: false,
  }, {
    name: "AdminCategoryApprovalByRole",
    type: "feature",
    category: "Management Features",
    value: false,
  }],
}, {
  orgId: "2222a7cd-0d58-11ef-83a2-06a19a0b1f5d",
  orgName: "Management 2",
  orgType: 2,
  organisations: [{
    orgId: "33333f59a-4976-11ed-af5d-021feb88a3f6",
    orgName: "Submanagement ",
    orgType: 2,
    features: [{
      name: "AdvancedAdminApprovalLevels",
      type: "feature",
      category: "Management Features",
      value: false,
    }, {
      name: "AdminCategoryApprovalByRole",
      type: "feature",
      category: "Management Features",
      value: false,
    }],
  }],
  features: [{
    name: "AdvancedAdminApprovalLevels",
    type: "feature",
    category: "Management Features",
    value: false,
  }, {
    name: "AdminCategoryApprovalByRole",
    type: "feature",
    category: "Management Features",
    value: false,
  }],
}, {
  orgId: "4444a7cd-0d58-11ef-83a2-06a19a0b1f5d",
  orgName: "Management 3",
  orgType: 2,
  organisations: [],
  features: [{
    name: "AdvancedAdminApprovalLevels",
    type: "feature",
    category: "Management Features",
    value: false,
  }, {
    name: "AdminCategoryApprovalByRole",
    type: "feature",
    category: "Management Features",
    value: false,
  }],
}];

Мне нужна функция, которая сопоставляет ее с новым массивом, где, если строка, указанная === name в объектах массива функций, тогда значение должно быть изменено на значение, указанное в параметре.

Итак, если я вызову функцию типа

handleTopLevelToggle('AdvancedAdminApprovalLevels', true);

Я должен вернуть те же вложенные массивы, но со значением, измененным на true для всех с именем «AdvancedAdminApprovalLevels» на всех вложенных уровнях.

Решение, с которого я начал, было

const handleTopLevelToggle = (value, fSwitch) => {
  const mappedArray = switches.map((swtch) => {
    swtch.features.map((feature) => {
      if (feature.name === fSwitch) {
        return { ...swtch, value: value };
      }
      return swtch;
    });
  });

  return mappedArray;
};
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
57
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

Ваше текущее решение находится на правильном пути, но у него есть несколько проблем.

  1. Вы ничего не возвращаете из функции внешней карты, которая приведет к неопределенным значениям в вашем MappedArray.
  2. Ты не обработка массива вложенных организаций.
  3. Вы заменяете весь объект переключения новым значением, а не просто обновляете свойство значения соответствующего объекта.

Пересмотренная функция:

const handleTopLevelToggle = (fSwitch: string, value: boolean) => {
  const mapFeatures = (features) => {
    return features.map((feature) => {
      if (feature.name === fSwitch) {
        return { ...feature, value: value };
      }
      return feature;
    });
  };

  const mapOrganisations = (organisations) => {
    return organisations.map((org) => {
      return { ...org, features: mapFeatures(org.features) };
    });
  };

  const mappedArray = switches.map((swtch) => {
    return {
      ...swtch,
      features: mapFeatures(swtch.features),
      organisations: mapOrganisations(swtch.organisations),
    };
  });

  return mappedArray;
};

Это самое интуитивное решение из всех. Спасибо.

dariusz 31.05.2024 18:01

Вам просто нужна простая рекурсивная функция:

const handleTopLevelToggle = (data, name, value) => {
  const toggle = (organisations) => organisations?.map((o) => ({
    ...o,
    features: o.features.map((f) => ({
      ...f,
      value: f.name === name ? value : f.value
    })),
    organisations: toggle(o.organisations)
  }));
  return toggle(data);
};

Полный фрагмент:

const switches = [
  {
    orgId: "1111a7cd-0d58-11ef-83a2-06a19a0b1f5d",
    orgName: "Management 1",
    orgType: 2,
    organisations: [],
    features: [
      {
        name: "AdvancedAdminApprovalLevels",
        type: "feature",
        category: "Management Features",
        value: false,
      },
      {
        name: "AdminCategoryApprovalByRole",
        type: "feature",
        category: "Management Features",
        value: false,
      },
    ],
  },
  {
    orgId: "2222a7cd-0d58-11ef-83a2-06a19a0b1f5d",
    orgName: "Management 2",
    orgType: 2,
    organisations: [
      {
        orgId: "33333f59a-4976-11ed-af5d-021feb88a3f6",
        orgName: "Submanagement ",
        orgType: 2,
        features: [
          {
            name: "AdvancedAdminApprovalLevels",
            type: "feature",
            category: "Management Features",
            value: false,
          },
          {
            name: "AdminCategoryApprovalByRole",
            type: "feature",
            category: "Management Features",
            value: false,
          },
        ],
      },
    ],
    features: [
      {
        name: "AdvancedAdminApprovalLevels",
        type: "feature",
        category: "Management Features",
        value: false,
      },
      {
        name: "AdminCategoryApprovalByRole",
        type: "feature",
        category: "Management Features",
        value: false,
      },
    ],
  },
  {
    orgId: "4444a7cd-0d58-11ef-83a2-06a19a0b1f5d",
    orgName: "Management 3",
    orgType: 2,
    organisations: [],
    features: [
      {
        name: "AdvancedAdminApprovalLevels",
        type: "feature",
        category: "Management Features",
        value: false,
      },
      {
        name: "AdminCategoryApprovalByRole",
        type: "feature",
        category: "Management Features",
        value: false,
      },
    ],
  },
];

const handleTopLevelToggle = (data, name, value) => {
  const toggle = (organisations) => organisations?.map((o) => ({
    ...o,
    features: o.features.map((f) => ({
      ...f,
      value: f.name === name ? value : f.value
    })),
    organisations: toggle(o.organisations)
  }));
  return toggle(data);
};

console.info(handleTopLevelToggle(switches, 'AdvancedAdminApprovalLevels', true));

Вы можете использовать рекурсивный подход и рассматривать массивы как значения.

const
    switches = [{ orgId: "1111a7cd-0d58-11ef-83a2-06a19a0b1f5d", orgName: "Management 1", orgType: 2, organisations: [], features: [{ name: "AdvancedAdminApprovalLevels", type: "feature", category: "Management Features", value: false }, { name: "AdminCategoryApprovalByRole", type: "feature", category: "Management Features", value: false }] }, { orgId: "2222a7cd-0d58-11ef-83a2-06a19a0b1f5d", orgName: "Management 2", orgType: 2, organisations: [{ orgId: "33333f59a-4976-11ed-af5d-021feb88a3f6", orgName: "Submanagement ", orgType: 2, features: [{ name: "AdvancedAdminApprovalLevels", type: "feature", category: "Management Features", value: false }, { name: "AdminCategoryApprovalByRole", type: "feature", category: "Management Features", value: false }] }], features: [{ name: "AdvancedAdminApprovalLevels", type: "feature", category: "Management Features", value: false }, { name: "AdminCategoryApprovalByRole", type: "feature", category: "Management Features", value: false }] }, { orgId: "4444a7cd-0d58-11ef-83a2-06a19a0b1f5d", orgName: "Management 3", orgType: 2, organisations: [], features: [{ name: "AdvancedAdminApprovalLevels", type: "feature", category: "Management Features", value: false }, { name: "AdminCategoryApprovalByRole", type: "feature", category: "Management Features", value: false }] }],
    change = (array, name, value) => array.map(object => Object.fromEntries(Object
        .entries(object)
        .map(([k, v]) => [
            k,
            Array.isArray(v)
                ? change(v, name, value)
                :  k === 'value' && object.name === name
                    ? value
                    : v
        ])
    )),
    result = change(switches, 'AdvancedAdminApprovalLevels', true);

console.info(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

В зависимости от того, что необходимо изменить, решение будет разным. Например. для неглубокого изменения (все ссылки на объекты останутся прежними) вы можете использовать

function changeAllFor(object:any, key:string,value:any){
    if (!object)return;
    if (Array.isArray(object)){
        for(let i = 0; i < object.length; i++){
            changeAllFor(object[i], key, value);
        }
        return;
    }
    if (typeof object !== 'object')return;
    const keys = Object.keys(object);
    for(let i = 0; i < keys.length; i++){
        if (keys[i] === key){
            object[keys[i]] = value;
        }
        if (typeof object[keys[i]] === 'object'){
            changeAllFor(object[keys[i]], key, value);
        }
    }
}

Если вам нужны новые ссылки на объекты (например, для сравнения на уровне объекта), я бы выбрал:

function createNewFor(object,key,value){
    if (!object)return object; //undefined or null
    if (Array.isArray(object)){
        return object.map((item) => createNewFor(item, key, value));
    }
    if (typeof object !== 'object')return object;
    const keys = Object.keys(object);
    const newObject = {...object};
    for(let i = 0; i < keys.length; i++){
        if (keys[i] === key){
            newObject[keys[i]] = value;
        }else{
            newObject[keys[i]] = createNewFor(object[keys[i]], key, value);
        }
    }
}

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