0

I have nested objects in array and i want to convert them into dot notation string with javascript.

This is my data sample data for converting process.

[
  {
    property: 'name',
    children: [],
    message: 'name should not be empty',
  },
  {
    property: 'priceForm',
    children: [
      {
        property: 'priceCurrency',
        children: [],
        message: 'priceCurrency should not be empty',
      },
    ],
  },
  {
    property: 'priceForm',
    children: [
      {
        property: 'rolePrices',
        children: [
          {
            property: '0',
            children: [
              {
                property: 'markupType',
                children: [],
                message: 'markupType should not be empty',
              },
            ],
          },
        ],
      },
    ],
  },
]

Expected result is

{
  'name': 'name should not be empty',
  'priceForm.priceCurrency': 'priceCurrency should not be empty',
  'priceForm.rolePrices.0.markupType': 'markupType should not be empty',
}
2
  • 1
    What happens if there's more than 1 element inside children? Commented Aug 9, 2019 at 15:45
  • for example 'priceForm.rolePrices.0.markupType1': 'markupType1 should not be empty', 'priceForm.rolePrices.1.markupType2': 'markupType2 should not be empty', 'priceForm.rolePrices.2.markupType3': 'markupType3 should not be empty' Commented Aug 9, 2019 at 15:46

3 Answers 3

2

You could collect the path first and then build a property.

function getObject(array, path = '', target = {}) {
    array.forEach(({ property, children = [], message }) => {
        var temp = path + (path && '.') + property;
        if (children.length) {
            getObject(children, temp, target);
            return;
        }
        target[temp] = message;
    });
    return target;   
}

var array = [{ property: 'name', children: [], message: 'name should not be empty' }, { property: 'priceForm', children: [{ property: 'priceCurrency', children: [], message: 'priceCurrency should not be empty' }] }, { property: 'priceForm', children: [{ property: 'rolePrices', children: [{ property: '0', children: [{ property: 'markupType', children: [], message: 'markupType should not be empty' }] }] }] }],
    object = getObject(array);
    
console.log(object);

Sign up to request clarification or add additional context in comments.

Comments

0

You can use recursive function to format you want.

const data = [{ property: 'name', children: [], message: 'name should not be empty' }, { property: 'priceForm', children: [{ property: 'priceCurrency', children: [], message: 'priceCurrency should not be empty' }] }, { property: 'priceForm', children: [{ property: 'rolePrices', children: [{ property: '0', children: [{ property: 'markupType', children: [], message: 'markupType should not be empty' }] }] }] }];

let result = {};
function format(data, prefix) {
    prefix = prefix ? `${prefix}.` : ''
    let message = ''
    data.forEach(i => {
        prefix = `${prefix}${i.property}`
        message = i.message
        if (!i.children.length) {
            i.message && (result[prefix] = i.message)
        } else {
            let child_data = format(i.children, prefix)
            child_data['message'] && child_data['prefix'] && (result[`${prefix}.${child_data['prefix']}`] = child_data['message'])
        }
        prefix = ''
    })

    return {prefix: prefix, message: message}
}

format(data)

console.log(result)

2 Comments

Not quite the output OP asked for.
Yes, I forgot to clear prefix. Now its OK. Thanks :)
0

Here you go! Array.reduce and recursion is a good fit for this problem.

const foo = (data, prefix = "") =>
  data.reduce(
    (acc, { property, message, children }) => ({
      ...acc,
      ...(children.length
        ? foo(children, `${prefix}${property}.`)
        : { [`${prefix}${property}`]: message })
    }),
    {}
  );

const data = [
  {
    property: "name",
    children: [],
    message: "name should not be empty"
  },
  {
    property: "priceForm",
    children: [
      {
        property: "priceCurrency",
        children: [],
        message: "priceCurrency should not be empty"
      }
    ]
  },
  {
    property: "priceForm",
    children: [
      {
        property: "rolePrices",
        children: [
          {
            property: "0",
            children: [
              {
                property: "markupType",
                children: [],
                message: "markupType should not be empty"
              },
              {
                property: "sibling!",
                children: [],
                message: "added a sibling to the input data"
              }
            ]
          }
        ]
      }
    ]
  }
];


console.log(foo(data));

Update cleaned up a bit. Basically a one liner now 🙌 Added a sibling to the input data too

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.