skip to Main Content

I have array of objects with a multi-level nesting.

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,
  }],
}];

What I want is the function to map it to new array where if the string provided === name in features array objects then value should be changed to the value provided in parameter.

So if I call the function like

handleTopLevelToggle('AdvancedAdminApprovalLevels', true);

I should return the same nested arrays but with value changed to true for all the with name ‘AdvancedAdminApprovalLevels’, on all nested levels.

Te solution I’ve started with was

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;
};

4

Answers


  1. Your current solution is on the right track, but it has a few issues.

    1. You are not returning anything from the outer map function, which
      will result in undefined values in your mappedArray.
    2. You are not
      handling the nested organisations array.
    3. You are replacing the entire swtch object with a new value, instead of just updating the value property of the matching feature.

    Revised Function:

    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;
    };
    
    Login or Signup to reply.
  2. You just need a simple recursive function:

    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);
    };
    

    Complete snippet:

    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.log(handleTopLevelToggle(switches, 'AdvancedAdminApprovalLevels', true));
    Login or Signup to reply.
  3. You could use a recursive approach and have a look to arrays as values.

    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.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    Login or Signup to reply.
  4. Depending on what needs to be changed the solution will differ. E.g. for a shallow change (all object references will stay the same) you could go with

    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);
            }
        }
    }
    

    If you need new object references (e.g. for a compare on object level) i’d go with:

    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);
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search