1

I am creating normally table rows and columns when I am using the simple map function with the data shown below, that works just fine:

const tableRows = [
      {
        name: 'SickLeave difference',
        januaryPayment: '-12000',
        febrauaryPayment: '0',
      },
      {
        name: 'Holiday difference',
        januaryPayment: '10000',
        febrauaryPayment: '25000',
      },
      {
        name: 'Result',
        januaryPayment: '0',
        febrauaryPayment: '23000',
      },
    ];

    <Table headerTextCodes={headerTextCodes} allowFormattedHeader={false}>
      { tableRows.map(row => (
        <TableRow>
          <TableColumn>
            { row.name }
          </TableColumn>
          <TableColumn>
            { row.januaryPayment }
          </TableColumn>
          <TableColumn>
            { row.febrauaryPayment }
          </TableColumn>
        </TableRow>
      ))
      }
    </Table>

But, when I am trying to create table rows and columns where I am creating the data by first formatting the result that I am mocking currently as a backend response:

const result = {
      periodFrom: '2018-05-01',
      periodTo: '2018-07-31',
      sumDifference: 17873,
      periodsPerReceiver: [
        {
          receiverType: {
            code: 'ARBG_PRIV',
            name: null,
          },
          resultsPerMonth: [
            {
              from: '2018-05-01',
              to: '2018-05-31',
              resultPerField: [
                {
                  fieldCode: {
                    code: 'SP',
                    name: null,
                  },
                  previouslyPayed: 0,
                  newAmount: 2662,
                  difference: 2662,
                },
              ],
              isNewPaymentPeriod: false,
            },
            {
              from: '2018-06-01',
              to: '2018-06-30',
              resultPerField: [
                {
                  fieldCode: {
                    code: 'FP',
                    name: null,
                  },
                  paid: 6899,
                  newAmount: 0,
                  difference: -6899,
                },
              ],
              isNewPaymentPeriod: false,
            },
            {
              from: '2018-07-01',
              to: '2018-07-31',
              resultPerField: [
                {
                  fieldCode: {
                    code: 'FP',
                    name: null,
                  },
                  paid: 0,
                  newAmount: 20012,
                  difference: 20012,
                },
              ],
              isNewPaymentPeriod: false,
            },
          ],
        },
        {
          receiverType: {
            code: 'BRUKER',
            name: null,
          },
          resultsPerMonth: [
            {
              from: '2018-05-01',
              to: '2018-05-31',
              resultPerField: [
                {
                  fieldCode: {
                    code: 'FP',
                    name: null,
                  },
                  paid: 0,
                  newAmount: 0,
                  difference: 0,
                },
              ],
              isNewPaymentPeriod: false,
            },
            {
              from: '2018-06-01',
              to: '2018-06-30',
              resultPerField: [
                {
                  fieldCode: {
                    code: 'FP',
                    name: null,
                  },
                  paid: 0,
                  newAmount: 2098,
                  difference: 2098,
                },
              ],
              isNewPaymentPeriod: false,
            },
            {
              from: '2018-07-01',
              to: '2018-07-31',
              resultPerField: [
                {
                  fieldCode: {
                    code: 'FP',
                    name: null,
                  },
                  paid: 0,
                  newAmount: 0,
                  difference: 0,
                },
              ],
              isNewPaymentPeriod: false,
            },
          ],
        },
      ],
    };

I have created this function to structure data in the way I could use it to create table and table rows later in the render function:

const resultPerReceiver = (receiver) => {
  const receiverObject = {
    receiver: receiver.receiverType,
    fields: [],
  };

  receiver.resultsPerMonth.forEach((monthResult) => {
    monthResult.resultPerFields.forEach((resultPerField) => {
      const fieldExists = receiverObject.field.find(e => e.field.code === resultPerField.fieldCode.code);
      if (fieldExists) {
        fieldExists.rows.forEach((row) => {
          const rowExists = row.resultPerMonth.find(e => e.from === monthResult.from);
          if (!rowExists) {
            const newAmount = {
              from: monthResult.from,
              to: monthResult.to,
              amount: resultPerField.newAmount,
            };
            const paid = {
              from: monthResult.from,
              to: monthResult.to,
              amount: resultPerField.paid,
            };
            const difference = {
              from: monthResult.from,
              to: monthResult.to,
              amount: resultPerField.difference,
            };
            fieldExists.rows.find(e => e.name === 'newAmount').resultPerMonth.push(newAmount);
            fieldExists.rows.find(e => e.name === 'paid').resultPerMonth.push(paid);
            fieldExists.rows.find(e => e.name === 'difference').resultPerMonth.push(difference);
          }
        });
      } else {
        receiverObject.field.push({
          field: resultPerField.fieldCode,
          rows: [
            {
              name: 'newAmount',
              resultPerMonth: [
                {
                  from: monthResult.from,
                  to: monthResult.to,
                  amount: resultPerField.newAmount,
                },
              ],
            },
            {
              name: 'paid',
              resultPerMonth: [
                {
                  from: monthResult.from,
                  to: monthResult.to,
                  amount: resultPerField.paid,
                },
              ],
            },
            {
              name: 'difference',
              resultPerMonth: [
                {
                  from: monthResult.from,
                  to: monthResult.to,
                  amount: resultPerField.difference,
                },
              ],
            },
          ],
        });
      }
    });
  });

  return receiverObject;
};

const formattedResult = result.periodsPerReceiver.map(receiver => resultPerReceiver(receiver));

This gives the result that looks something like this:

const formattedResult = [ 
  {
    receiver: {code: "ARBG_PRIV", name: null },
    fields: [
      { field: { code: "SP", name: null },
        rows: [
          {name: "newAmount", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          },
          {name: "paid", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          },
          {name: "difference", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          }
        ]
      },
      { field: { code: "FP", name: null },
        rows: [
          {name: "newAmount", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          },
          {name: "paid", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          },
          {name: "difference", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          }
        ]
      },
    ]
  },
  {
    receiver: {code: "BRUKER", name: null },
    fields: [
      { field: { code: "SP", name: null },
        rows: [
          {name: "newAmount", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          },
          {name: "paid", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          },
          {name: "difference", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          }
        ]
      },
      { field: { code: "FP", name: null },
        rows: [
          {name: "newAmount", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          },
          {name: "paid", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          },
          {name: "difference", resultPerMonth: [
              {from: "2018-06-01", to: "2018-06-31", amount: 2662},
              {from: "2018-07-01", to: "2018-07-31", amount: 2662}
            ]
          }
        ]
      },
    ]
  },
]

Then, I am trying to render this result from the function like this in the render function:

<div className={styles.table}>
  {
    formattedResult.map(reciever => (
      <Table>
        { reciever.fields.map(field => field.rows.map(row => (
          <TableRow>
            <TableColumn>
              <Image
                tabIndex="0"
                className={styles.expandButton}
                src={arrowDownImageUrl}
                altCode="Timeline.openData"
              />
              { row.name }
            </TableColumn>
            { row.resultPerMonth.map(month => (
              <TableColumn>
                { month.amount }
              </TableColumn>
            ))}
          </TableRow>
        )))}
      </Table>
    ))}
</div>

But, when I try to do it like that, I get an error:

Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. in tbody (created by Table)

I have checked all the imports in the component, and I am importing them right, because this error is not happening when I am rendering the simple data shown above. I have no idea why is this happening in the latter case, what am I doing wrong?

Here you can see the sandbox for it.

1
  • 2
    Anyway, It safer to check children && children.length ... Commented Oct 18, 2018 at 14:33

1 Answer 1

3
+50

In your second case, you are using forEach which returns undefined. You should use map in order to get an array.

Be careful in your case, you will get an array of arrays. Maybe you should use flatMap from lodash or the spread operator.

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

3 Comments

I have updated the question, I have changed the function because I am creating rows with different data, and I am using nested maps, instead of forEach, but now I am getting a different error. I have also created a sandbox where it is easier to see what is the problem.
This problem is because you're returning an array of arrays : you have to flatten the result. I made a fork of your code codesandbox.io/s/zq2mxzlmzl. The [].concat(...prev) at line 38 in index.js is an equivalent of a flatten. It seems to be working for me :)
Thanks, that was it!

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.