0

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',

}

3 Answers 3

1

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.

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

Comments

0

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;
    }, {});

Comments

0

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))

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.