I'm currently building a budgeting application with React and JavaScript. Right now I'm able to print a table of costs like shown below.
Name | Budget | Used $ | Used % | Available |
---|---|---|---|---|
Food | 300 | 300 | 100 | 0 |
Streaming services | 600 | 600 | 100 | 0 |
Here is the code where I fetch data and map through each item to the table:
<tbody>
{expenses.budgetedAmounts
.sort((a, b) => {
return a.department < b.department;
})
.map((item, index) => (
<tr
key={index}
>
<td>
{item.name}
</td>
<td>
{item.budgetedExpense}
</td>
<td>
{item.actualExpense}
</td>
<td>
{item.percentageUsed}
</td>
<td>
{item.availableExpense}
</td>
</tr>
))}
</tbody>
I would also like to add sub-items to the table that show what the budget of each item consist of. For example, the budget set for food consists of french fries and apples.
Name | Budget | Used $ | Used % | Available |
---|---|---|---|---|
Food | 300 | 300 | 100 | 0 |
• French fries | 150 | |||
• Apples | 150 | |||
Streaming services | 600 | 600 | 100 | 0 |
• Netflix | 300 | |||
• Disney | 300 |
Subitems are also in array which can be accessed via "item". I'm thinking that I could just add another loop after the first map method:
{item.nestedItems.map((nested, secondIndex) =>
)}
And I could access items like this:
{nested.name} and {nested.price}
Data is fetched correctly, but I can't seem to figure out where to place nested loop in the code and how to achieve wanted table structure. I know this is probably hard question to answer without being able to try the code, but any ideas to help would be just great!
CodePudding user response:
You could first flatten your array, and then do that final map, taking some precautions that undefined properties do not result in undefined
outputs:
<tbody>
{expenses.budgetedAmounts
.sort((a, b) => a.department < b.department)
.flatMap(a => [a, ...a.nestedItems])
.map((item, index) => (
<tr key={index}>
<td>{item.name}</td>
<td>{item.budgetedExpense ?? item.price}</td>
<td>{item.actualExpense ?? ""}</td>
<td>{item.percentageUsed ?? ""}</td>
<td>{item.availableExpense ?? ""}</td>
</tr>
))}
</tbody>
Note that the index
now no longer corresponds with the original index in the non-flattened array. I assumed it just served as a unique reference, but if not, you may want to add some code to still have access to the original index.
CodePudding user response:
The simplest way to do this do exactly what you want to. Write another map right after the tag in the first map to render sub-item rows. Something like this:
<tbody>
{expenses.budgetedAmounts
.sort((a, b) => {
return a.department < b.department;
})
.map((item, index) => (
<><tr
key={index}
>
<td>
{item.name}
</td>
<td>
{item.budgetedExpense}
</td>
<td>
{item.actualExpense}
</td>
<td>
{item.percentageUsed}
</td>
<td>
{item.availableExpense}
</td>
</tr>
{item.nestedItems.map((nested, secondIndex) => <tr>
<td> {nested.name}</td> <td> {nested.price} </td>
</tr>)}</>
))}
</tbody>
CodePudding user response:
Try this
<tbody>
{ budgetedAmounts.map((item,index)=>{
return(
<>
<tr key={index "b"}>
<td>{item.name}</td>
<td>{item.budgetedExpense}</td>
<td>{item.actualExpense}</td>
<td>{item.percentageUsed}</td>
<td>{item.availableExpense}</td>
</tr>
{ item.subItem && item.subItem.map((subItem,subIndex)=>{
return(
<tr key={item.id " __ " subIndex}>
<td>{subItem.name}</td>
<td>{subItem.budgetedExpense}</td>
<td>{subItem.actualExpense}</td>
<td>{subItem.percentageUsed}</td>
<td>{subItem.availableExpense}</td>
</tr>
)
})
}
</>
)
})
}
</tbody>