skip to Main Content

I have a dynamic object myObj as below

{
    "section-1": {
        "id": "section-1",
        "fields": [
            {
                "id": "field1",
                "items": [
                    {
                        "display": "Select",
                        "value": "SELECT"
                    },
                    {
                        "display": "A 1",
                        "value": "A1"
                    },
                    {
                        "display": "A 2",
                        "value": "A2"
                    }
                ],
                "value": "A1"
            }, {
                "id": "field2",
                "items": [],
                "value": "Field 2"
            }
        ]
    },
    "section-2": {
        "id": "section-2",
        "fields": []
    },
    section-3": {
        "id": "section-3",
        "fields": []
    }
}

The sections and fields are both dynamic from API response. So, it can have n number of sections and n number of fields.

I want to extract "myDefaults" from within these objects which is the "value" attribute.

As of now, I am manually iterating through each section and then extracting field.value into myDefaults as below.
However, I am wondering if there can be any better way of writing this logic (probably ES6 way of writing), considering all the sections would have similar structure (just that there can be n number of sections with n number of fields within them)

const section1 = myObj?.sections['section-1'];
const section2 = myObj?.sections['section-2'];

let myDefaults = {};

section1.fields.forEach((field) => {
    myDefaults[field.id] = field.value;
    if (field.items && field.items.length > 0) {
        myDefaults[field.id] = field.items.find(item => item.value === field.value);
    }
});

section2.fields.forEach((field) => {
    myDefaults[field.id] = field.value;
    if (field.items && field.items.length > 0) {
        myDefaults[field.id] = field.items.find(item => item.value === field.value);
    }
});

3

Answers


  1. You can use Object.values to avoid hard-coding the section names.

    This code gets all sections, then for each section visits each field. It looks up the selected value in the list of items. Whether a match is found determines whether we just use the value or an object containing the value and the display property.

    Finally, we use Object.fromEntries to merge all of the [key, value] entries into a single object.

    const myObj = {"sections":{"section-1":{"id":"section-1","fields":[{"id":"field1","items":[{"display":"Select","value":"SELECT"},{"display":"A 1","value":"A1"},{"display":"A 2","value":"A2"}],"value":"A1"},{"id":"field2","items":[],"value":"Field 2"}]},"section-2":{"id":"section-2","fields":[]},"section-3":{"id":"section-3","fields":[]}}};
    
    console.log(
      Object.fromEntries(Object.values(myObj.sections)
        .flatMap(i => i.fields.map(({id, items, value}) => [
          id,
          items?.find(item => item.value===value) ?? value
        ]))
      )
    )
    Login or Signup to reply.
  2. This works for the object that you gave in the example. You can edit it to suit your business needs. Cheers!

     Object.keys(myObj) 
        .map(key=> myObj[key].fields)
        .flat()
        .reduce((result, fieldItem)=>{
            const {id, items, value } = fieldItem
            result[id] = items?.length ? 
                            items.find(i => i.value == value)
                            : value;
            return result;
        }, {})
    

    P.S. I haven’t thought of any edge cases though xD

    Login or Signup to reply.
  3. I have used your logic but used it in combination with Object.entries and Array#reduce:

    let myObj={sections:{"section-1":{id:"section-1",fields:[{id:"field1",items:[{display:"Select",value:"SELECT"},{display:"A 1",value:"A1"},{display:"A 2",value:"A2"}],value:"A1"},{id:"field2",items:[],value:"Field 2"}]},"section-2":{id:"section-2",fields:[]},"section-3":{id:"section-3",fields:[]}}};
    
    let result = Object.entries(myObj.sections).reduce((acc, [keys, values]) => {
    
      values.fields.forEach((field) => {
        acc[field.id] = field.value;
        if (field.items && field.items.length > 0) {
          acc[field.id] = field.items.find(item => item.value === field.value);
        }
       
      });
      
      return acc
    }, {})
    
    console.log(result)
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search