Retrieving and updating the property values from a multi-level nested object programatically

Vanu Protap Verma
4 min readJun 2, 2023

Context:

Recently, I was working on a task where I need to generate a web form dynamically based on a provided data structure (json payload).

It would have been a simple solution if the json payload was a flat object (no nested object).

However, in my case, it was not that simple. Because the input data structure was something similar like the below (this was the POST request payload structure of an API endpoint, where my web form is supposed to send the form data):

01. {
02. "data": {
03. "attributes": {
04. "uniqueId": "1234567890",
05. "studentData": {
06. "studentId": "STD-2023-011-017",
07. "lastName": "Doe",
08. "dateOfBirth": "2001-11-05"
09. }
10. },
11. "queryType": "SearchRequest"
12. }
13. }

As you can see in the above example, the payload has multiple level of nested object properties as well as non-object properties. According to this payload, my web form should have input fields for “uniqueId”, “studentId”, “lastName”, “dateOfBirth” and “queryType”.

Problem:

Now, when thinking about the solution, I actually had 2 problems in my hand:

  • Extracting the non-object property names to populate the web form

and

  • Update the values from submitted web form for related properties

Solution:

Extracting the non-object property names to populate the web form

After spending quite some time in thinking for an approach (and also trying to implement some of them) to solve these problems, I realised that I need an recursive function to loop through the nested objects.

However, one issue with therecursive function was, if the value of the current property is an object , then it would call the recursive function again (and may potentially skip the non-object property completely). To understand this issue little better, please refer to the line no. 03 and line no. 11 . Since the value of attributes property is an object , the recursive function was skipping evaluating queryType property completely.

So the code block that I finally ended up with to populate the input fields for my web form is like the below:

// function to check if a value is an object
// I agree that this function may not be a proper function
// to check if a value is an object or not, but is enough for my case
function isObject(value) {
if ((typeof value === 'object') && (typeof value !== 'function') && !!value) {
return true;
}
return false;
}


let formFields = []
let tempFormFieldObjectVal = {}

// function to populate web form fields
// @params payload // this is the payload structure provided above
function populateFormFields(payload) {

let shouldIterate = true

while (shouldIterate) {
let isObjectValueFound = false

let entries = Object.entries(payload);

// first I made sure to loop through
// all the properties that are in current level
entries.forEach(item => {
let key = item[0];
let val = item[1]

if (isObject(val)) {

isObjectValueFound = true
tempFormFieldObjectVal = val

} else {
// if any non-object property found
// I added that to the array
formFields.push(key)

}
})

// finally doing the recursion
// NOTE: haven't tested with more than 1 nested object
// in the same level though
if (isObjectValueFound) {
populateFormFields(tempFormFieldObjectVal)
}
shouldIterate = false
}
}

// main function, which calls populateFormFields
function execute() {
console.log(`\n ===== Executing ======\n`);

populateFormFields(payload);
/*
[
"queryType",
"uniqueId",
"studentId",
"lastName",
"dateOfBirth"
]
*/

console.log(`\n\n populateFormFields from execute fn: ${JSON.stringify(formFields, null, 2)}`)
}

Please note that since it was a proof-of-concept, I haven’t actually created any actual web form to use the populated fields.

Update the values from submitted web form for related properties

Now to solve the problem of updating the payload structure using the values received from the (assumed) web form, I assumed that the web form sent the form data as a flat json object (meaning no nested objects), like this:

// sampleFormData
{
"uniqueId": "some-linking-id",
"studentId": "some-student-id",
"lastName": "some-last-name",
"dateOfBirth": "some-date-of-birth",
"queryType": "some-query-type"
}

Using the similar approach of populating the input fields, I wrote another recursive function. The main trick that I used for this function is I used the reference of the object payload. So my code looks like this:


let tempObjVal = {};
let iteration = 0;

// this function updates the property values of the input payload object
function updateInputPayloadObjectValues(payload) {
let shouldIterate = true
iteration++

while (shouldIterate) {
let isObjectValueFound = false

let entries = Object.entries(payload);

entries.forEach(item => {
let key = item[0];
let val = item[1]

if (isObject(val)) {

isObjectValueFound = true
tempObjVal = val

} else {
// check if the current property is
// inside the sampleFormData or not
// if it is, then update current value with
// the value from sampleFormData
payload[key] = sampleFormData[key] || payload[key]

}
})

// finally doing the recursion
// NOTE: haven't tested with more than 1 nested object
// in the same level though
if (isObjectValueFound) {
updateInputPayloadObjectValues(tempObjVal)
}
shouldIterate = false
}
}

// main function which calls updateInputPayloadObjectValues()
function execute() {
// making a copy of the original input payload
let payloadToUpdate = JSON.parse(JSON.stringify(originalPayload));

// using the "reference" of the payloadToUpdate object
updateInputPayloadObjectValues(payloadToUpdate)

console.log(`\n\n updated request payload from execute fn: ${JSON.stringify(payloadToUpdate, null, 2)}`)

/*
{
"data": {
"attributes": {
"uniqueId": "some-linking-id",
"studentData": {
"studentId": "some-student-id",
"lastName": "some-last-name",
"dateOfBirth": "some-date-of-birth"
}
},
"queryType": "some-query-type"
}
}
*/
}

Disclaimer:

I agree that my code above may not be optimised, also it may not work for some other scenarios (i.e. multiple properties in same nesting level contain object values etc.). But at least for the scenario described above (and for similar scenarios), this approach can be a possible solution for populating input fields to dynamically populate an input form as well as updating the values inside the request payload object.

Thanks for sticking with me :)

--

--