Reputation: 1
I've been dealing with creating an object with reduce from a nested array. The object needs to have the _iud keys with the value of initialValue, from the object that contains both keys. I made a function that can iterate through them but can't return the new object with all the new properties I got. I've tried to use the shallow and deep copy to clone acc but can't make it :( Could anyone give me a hand?
This is the nested array
export const formData = [
{
component: 'page',
label: 'Page 1',
_uid: '0c946643-5a83-4545-baea-055b27b51e8a',
fields: [
{
component: 'field_group',
label: 'Name',
_uid: 'eb169f76-4cd9-4513-b673-87c5c7d27e02',
fields: [
{
component: 'text',
label: 'First Name',
initialValue: '2345432',
type: 'text',
_uid: '5b9b79d2-32f2-42a1-b89f-203dfc0b6b98',
},
{
component: 'text',
label: 'Last Name',
initialValue: '2345432',
type: 'text',
_uid: '6eff3638-80a7-4427-b07b-4c1be1c6b186',
},
],
},
{
component: 'text',
label: 'Email',
initialValue: '2345432',
type: 'email',
_uid: '7f885969-f8ba-40b9-bf5d-0d57bc9c6a8d',
},
{
component: 'text',
label: 'Phone',
initialValue: '2345432',
type: 'text',
_uid: 'f61233e8-565e-43d0-9c14-7d7f220c6020',
},
],
},
{
component: 'page',
label: 'Page 2',
_uid: '3a30803f-135f-442c-ab6e-d44d7d7a5164',
fields: [
{
component: 'options',
label: 'Radio Buttons',
type: 'radio',
initialValue: '2345432',
_uid: 'bd90f44a-d479-49ae-ad66-c2c475dca66b',
options: [
{
component: 'option',
label: 'Option 1',
value: 'one',
},
{
component: 'option',
label: 'Option 2',
value: 'two',
},
],
},
{
component: 'text',
label: 'Conditional Field',
type: 'text',
_uid: 'bd90f44a-d479-49ae-ad66-c2c475daa66b',
initialValue: '2345432',
conditional: {
value: 'two',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
},
],
},
{
component: 'page',
label: 'Page 3a',
_uid: 'cd392929-c62e-4cdb-b4dd-914035c1cc8d',
initialValue: '2345432',
conditional: {
value: 'one',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
fields: [
{
component: 'options',
label: 'More radio buttons',
type: 'radio',
_uid: 'a15bef56-ab67-4b98-a781-4441cc3bba56',
initialValue: '2345432',
options: [
{ component: 'option', label: 'Option 1', value: 'one' },
{ component: 'option', label: 'Option 2', value: 'two' },
],
},
],
},
{
component: 'page',
label: 'Page 3b',
_uid: '1dd4ec7c-fb53-47f4-af1b-1ab8f805b888',
conditional: {
value: 'two',
initialValue: '2345432',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
fields: [
{
component: 'options',
label: 'Something to toggle',
type: 'radio',
_uid: '3ca9237d-e225-4950-a298-f81ce996cb85',
options: [
{
component: 'option',
label: 'Option 1',
value: 'one',
},
{ component: 'option', label: 'Option 2', value: 'two' },
],
},
{
component: 'field_group',
label: 'Name',
_uid: 'b8406cb5-ff0d-4a83-a8f8-99740b6d91f7',
fields: [
{
component: 'text',
label: 'First Name',
initialValue: '2345432',
type: 'text',
_uid: 'c6e065e1-dbcb-44ea-831f-ac3af889e964',
},
{
component: 'text',
label: 'Last Name',
initialValue: '2345432',
type: 'text',
_uid: 'e279ba9c-3c9b-4df8-b267-d14b3c2adcdd',
},
],
},
{
component: 'text',
label: 'Email',
initialValue: '2345432',
type: 'email',
_uid: 'a95208a0-7673-48a8-b704-2fb408fa6eec',
},
{
component: 'text',
label: 'Phone',
initialValue: '2345432',
type: 'text',
_uid: '8dde5083-0619-42d6-8fc7-0563c35d03ad',
},
],
},
{
component: 'page',
label: 'Page 4',
_uid: '0c946643-5a83-4545-baea-065b27b51e8a',
fields: [
{
component: 'text',
label: 'Final Comment',
initialValue: '2345432',
type: 'text',
_uid: 'f61231e8-565e-43d0-9c14-7d7f220c6020',
},
],
},
]
The function:
function getInitialValues(formData = []) {
return Array.from(formData).reduce((acc, currentValue, idx) => {
const arrayOfStrings = ['page', 'field_group', 'options']
const str = currentValue.component
const found = arrayOfStrings.find((v) => str === v)
if (found) {
// console.log('entro', currentValue)
getInitialValues(currentValue?.fields)
return acc
}
if (
(currentValue.component === 'text' || currentValue.component === 'select') &&
currentValue.label === 'Conditional Field'
) {
acc[currentValue._uid] = currentValue?.initialValue
return acc
}
return acc
}, {})
}
My expected result is something like this from all the _uids that has initialValues (only for references)
{
5b9b79d2-32f2-42a1-b89f-203dfc0b6b98: '2345432',
5b9b79d2-32f2-42a1-b89f-203dfc0b6b97: '2345431',
5b9b79d2-32f2-42a1-b89f-203dfc0b6b96: '2345430',
}
Upvotes: 0
Views: 163
Reputation: 50787
I find it easier to separate the extraction of your _uid
/initialValue
properties from the formatting of these into an output object.
Here is a recursive extract
function and a simple convert
function that builds on it.
const extract = (xs) =>
xs .flatMap (({initialValue, _uid, fields = []}) =>
[[_uid, initialValue], ...extract (fields)]
) .filter (([_, init]) => init != null)
const convert = xs =>
Object .fromEntries (extract (xs))
const formData = [{component: "page", label: "Page 1", _uid: "0c946643-5a83-4545-baea-055b27b51e8a", fields: [{component: "field_group", label: "Name", _uid: "eb169f76-4cd9-4513-b673-87c5c7d27e02", fields: [{component: "text", label: "First Name", initialValue: "2345432", type: "text", _uid: "5b9b79d2-32f2-42a1-b89f-203dfc0b6b98"}, {component: "text", label: "Last Name", initialValue: "2345432", type: "text", _uid: "6eff3638-80a7-4427-b07b-4c1be1c6b186"}]}, {component: "text", label: "Email", initialValue: "2345432", type: "email", _uid: "7f885969-f8ba-40b9-bf5d-0d57bc9c6a8d"}, {component: "text", label: "Phone", initialValue: "2345432", type: "text", _uid: "f61233e8-565e-43d0-9c14-7d7f220c6020"}]}, {component: "page", label: "Page 2", _uid: "3a30803f-135f-442c-ab6e-d44d7d7a5164", fields: [{component: "options", label: "Radio Buttons", type: "radio", initialValue: "2345432", _uid: "bd90f44a-d479-49ae-ad66-c2c475dca66b", options: [{component: "option", label: "Option 1", value: "one"}, {component: "option", label: "Option 2", value: "two"}]}, {component: "text", label: "Conditional Field", type: "text", _uid: "bd90f44a-d479-49ae-ad66-c2c475daa66b", initialValue: "2345432", conditional: {value: "two", field: "3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b"}}]}, {component: "page", label: "Page 3a", _uid: "cd392929-c62e-4cdb-b4dd-914035c1cc8d", initialValue: "2345432", conditional: {value: "one", field: "3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b"}, fields: [{component: "options", label: "More radio buttons", type: "radio", _uid: "a15bef56-ab67-4b98-a781-4441cc3bba56", initialValue: "2345432", options: [{component: "option", label: "Option 1", value: "one"}, {component: "option", label: "Option 2", value: "two"}]}]}, {component: "page", label: "Page 3b", _uid: "1dd4ec7c-fb53-47f4-af1b-1ab8f805b888", conditional: {value: "two", initialValue: "2345432", field: "3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b"}, fields: [{component: "options", label: "Something to toggle", type: "radio", _uid: "3ca9237d-e225-4950-a298-f81ce996cb85", options: [{component: "option", label: "Option 1", value: "one"}, {component: "option", label: "Option 2", value: "two"}]}, {component: "field_group", label: "Name", _uid: "b8406cb5-ff0d-4a83-a8f8-99740b6d91f7", fields: [{component: "text", label: "First Name", initialValue: "2345432", type: "text", _uid: "c6e065e1-dbcb-44ea-831f-ac3af889e964"}, {component: "text", label: "Last Name", initialValue: "2345432", type: "text", _uid: "e279ba9c-3c9b-4df8-b267-d14b3c2adcdd"}]}, {component: "text", label: "Email", initialValue: "2345432", type: "email", _uid: "a95208a0-7673-48a8-b704-2fb408fa6eec"}, {component: "text", label: "Phone", initialValue: "2345432", type: "text", _uid: "8dde5083-0619-42d6-8fc7-0563c35d03ad"}]}, {component: "page", label: "Page 4", _uid: "0c946643-5a83-4545-baea-065b27b51e8a", fields: [{component: "text", label: "Final Comment", initialValue: "2345432", type: "text", _uid: "f61231e8-565e-43d0-9c14-7d7f220c6020"}]}]
console .log (convert (formData))
.as-console-wrapper {max-height: 100% !important; top: 0}
The question also seems to imply that you want to do an update of the data. I would think of that as a separate step, which you already seem to be able to do.
Upvotes: 1
Reputation: 23654
I found a simple forEach
loop with recursion to be easier.
const formData = [{
component: 'page',
label: 'Page 1',
_uid: '0c946643-5a83-4545-baea-055b27b51e8a',
fields: [{
component: 'field_group',
label: 'Name',
_uid: 'eb169f76-4cd9-4513-b673-87c5c7d27e02',
fields: [{
component: 'text',
label: 'First Name',
initialValue: '2345432',
type: 'text',
_uid: '5b9b79d2-32f2-42a1-b89f-203dfc0b6b98',
},
{
component: 'text',
label: 'Last Name',
initialValue: '2345432',
type: 'text',
_uid: '6eff3638-80a7-4427-b07b-4c1be1c6b186',
},
],
},
{
component: 'text',
label: 'Email',
initialValue: '2345432',
type: 'email',
_uid: '7f885969-f8ba-40b9-bf5d-0d57bc9c6a8d',
},
{
component: 'text',
label: 'Phone',
initialValue: '2345432',
type: 'text',
_uid: 'f61233e8-565e-43d0-9c14-7d7f220c6020',
},
],
},
{
component: 'page',
label: 'Page 2',
_uid: '3a30803f-135f-442c-ab6e-d44d7d7a5164',
fields: [{
component: 'options',
label: 'Radio Buttons',
type: 'radio',
initialValue: '2345432',
_uid: 'bd90f44a-d479-49ae-ad66-c2c475dca66b',
options: [{
component: 'option',
label: 'Option 1',
value: 'one',
},
{
component: 'option',
label: 'Option 2',
value: 'two',
},
],
},
{
component: 'text',
label: 'Conditional Field',
type: 'text',
_uid: 'bd90f44a-d479-49ae-ad66-c2c475daa66b',
initialValue: '2345432',
conditional: {
value: 'two',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
},
],
},
{
component: 'page',
label: 'Page 3a',
_uid: 'cd392929-c62e-4cdb-b4dd-914035c1cc8d',
initialValue: '2345432',
conditional: {
value: 'one',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
fields: [{
component: 'options',
label: 'More radio buttons',
type: 'radio',
_uid: 'a15bef56-ab67-4b98-a781-4441cc3bba56',
initialValue: '2345432',
options: [{
component: 'option',
label: 'Option 1',
value: 'one'
},
{
component: 'option',
label: 'Option 2',
value: 'two'
},
],
}, ],
},
{
component: 'page',
label: 'Page 3b',
_uid: '1dd4ec7c-fb53-47f4-af1b-1ab8f805b888',
conditional: {
value: 'two',
initialValue: '2345432',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
fields: [{
component: 'options',
label: 'Something to toggle',
type: 'radio',
_uid: '3ca9237d-e225-4950-a298-f81ce996cb85',
options: [{
component: 'option',
label: 'Option 1',
value: 'one',
},
{
component: 'option',
label: 'Option 2',
value: 'two'
},
],
},
{
component: 'field_group',
label: 'Name',
_uid: 'b8406cb5-ff0d-4a83-a8f8-99740b6d91f7',
fields: [{
component: 'text',
label: 'First Name',
initialValue: '2345432',
type: 'text',
_uid: 'c6e065e1-dbcb-44ea-831f-ac3af889e964',
},
{
component: 'text',
label: 'Last Name',
initialValue: '2345432',
type: 'text',
_uid: 'e279ba9c-3c9b-4df8-b267-d14b3c2adcdd',
},
],
},
{
component: 'text',
label: 'Email',
initialValue: '2345432',
type: 'email',
_uid: 'a95208a0-7673-48a8-b704-2fb408fa6eec',
},
{
component: 'text',
label: 'Phone',
initialValue: '2345432',
type: 'text',
_uid: '8dde5083-0619-42d6-8fc7-0563c35d03ad',
},
],
},
{
component: 'page',
label: 'Page 4',
_uid: '0c946643-5a83-4545-baea-065b27b51e8a',
fields: [{
component: 'text',
label: 'Final Comment',
initialValue: '2345432',
type: 'text',
_uid: 'f61231e8-565e-43d0-9c14-7d7f220c6020',
}, ],
},
]
function getInitialValues(formData = [], output=[]) {
formData.forEach(obj => {
// first check for the Conditional Field label
let found = obj.hasOwnProperty('label') && obj.label === "Conditional Field";
// then loop through the component fields if neccesary
if (!found) ['select','text','options'].forEach(val => {
if (obj.hasOwnProperty('component') && obj.component === val) found = true;})
// if found update the output array
if (found) output.push({[obj._uid]: obj.initialValue})
// check for recursion
if (obj.hasOwnProperty('fields')) output = getInitialValues(obj.fields, output)
})
return output;
}
console.log(getInitialValues(formData))
Upvotes: 0
Reputation: 53525
The problem is in:
if (found) {
// console.log('entro', currentValue)
getInitialValues(currentValue?.fields)
return acc
}
this call to getInitialValues
is supposed to return a result that is not saved into acc
.
One way to correct it is to do something like this:
if (found) {
const res = getInitialValues(currentValue.fields);
return Object.assign(acc, res);
}
There may be other issues as well, but this is the one that stood up for me.
Note: two out of three of the uids in the "expected results" do not appear in the first code snippet (the example of formData
).
As for the other one (with uid: 5b9b79d2-32f2-42a1-b89f-203dfc0b6b98
) it has a label
of 'First Name'
not 'Conditional Field'
- that's why it doesn't show up in the output.
(Full) Corrected code
function getInitialValues (formData = []) {
return formData.reduce((acc, currentValue) => {
const arrayOfStrings = ['page', 'field_group', 'options'];
const str = currentValue.component;
const found = arrayOfStrings.find((v) => str === v);
if (found) {
const res = getInitialValues(currentValue.fields);
return Object.assign(acc, res);
}
if (
(currentValue.component === 'text' || currentValue.component === 'select') &&
currentValue.label === 'Conditional Field'
) {
if (currentValue.initialValue) {
acc[currentValue._uid] = currentValue.initialValue;
}
}
return acc;
}, {});
Upvotes: 0