Home > Enterprise >  How to change value of all properties within a nested JSON object?
How to change value of all properties within a nested JSON object?

Time:10-28

I'm trying to get a key/property from a JSON object and change all of its values, whether its nested within another object, or by itself.

I have a locale variable

const locale = "en" 

and I'm trying to change the value of the returned json object depending on locale, such as

result.navTitle = result.navTitle[locale]

or

stories.map((story)=> story.navTitle = story.navTitle[locale]);
...etc
result = [
{
    "data":{
        "en":"English",
        "fi":"Finnish"
    },
    "navTitle":{
        "en":"English",
        "fi":"Finnish"
    },
    "stories": [
       {
        "navTitle":{"en":"English","fi":"Finnish"},
        "cards":[
            {
                "navTitle":{"en":"English","fi":"Finnish"}
            },
             {
                "navTitle":{"en":"English","fi":"Finnish"}
            }
        ]
       },
       {
        "navTitle":{"en":"English","fi":"Finnish"}
       }
    ]
}
]

I have managed to do this with repetitive .map functions but it gets long, is there any other alternative to do this?

CodePudding user response:

You can use recursion,.

Basically just check if array of object, if array simply map, if it's an object you can use Object.entries / fromEntries to change, inside the loop of the Object.entries you can then test for the lang, if the values of the entries are an object, just pass this to itself for the recursion bit.

Example below..

const result = [{"data":{"en":"English","fi":"Finnish"},"navTitle":{"en":"English","fi":"Finnish"},"stories":[{"navTitle":{"en":"English","fi":"Finnish"},"cards":[{"navTitle":{"en":"English","fi":"Finnish"}},{"navTitle":{"en":"English","fi":"Finnish"}}]},{"navTitle":{"en":"English","fi":"Finnish"}}]}];

function langObj(lang, obj) {
  if (typeof obj === 'object') {
    if (Array.isArray(obj)) {
      return obj.map(m => langObj(lang, m));
    } else {
      return Object.fromEntries(
        Object.entries(obj).map(([k,v]) => {
          const x = v[lang] || v;
          return [k, langObj(lang, x)];
        })
      );
    }
  } else {
    return obj;
  }
}

console.log('English');
console.log(langObj('en', result));
console.log('Finnish');
console.log(langObj('fi', result));
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

You can create a function, say getLocaleData() to get the relevant data for each locale, adopting a recursive approach to selectively clone the input data.

Once we reach a child object with properties like 'en', 'fi' etc, we'll return only the property that matches the desired locale.

const result = [ { "data":{ "en":"English", "fi":"Finnish" }, "navTitle":{ "en":"English", "fi":"Finnish" }, "stories": [ { "navTitle":{"en":"English","fi":"Finnish"}, "cards":[ { "navTitle":{"en":"English","fi":"Finnish"} }, { "navTitle":{"en":"English","fi":"Finnish"} } ] }, { "navTitle":{"en":"English","fi":"Finnish"} } ] } ]

function getLocaleData(obj, locale) {
    if (!obj) return obj;
    // If a property key is 'en', 'fi' etc, return the value.
    if (typeof(obj[locale]) === 'string') return obj[locale];
    let result = Array.isArray(obj) ? [] : {};
    for (let k in obj) {
        result[k] = (typeof(obj[k]) === "object") ? getLocaleData(obj[k], locale): obj[k];
    }
    return result;
}

console.log('\nEnglish data:', getLocaleData(result, 'en'));
console.log('\nFinnish data:', getLocaleData(result, 'fi'))
.as-console-wrapper { max-height: 100% !important; top: 0; }
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related