how to map subarray by key of parent array reactjs - reactjs

how to map subarray in react based on key of parent array?
I have tried mapping by id key of main array to map elements of dish_count array
<TableCell align="left">
{this.state.persons.map((items,name) =>
<div key={this.state.persons.id}>
{(typeof(items.dish_count)=="object")? (<div>
{ items.dish_count.map((subdata) =>
<table>
<td >
{subdata.meal_type}
</td>
</table>
)
}
</div>): (null)}</div>)}
</TableCell>
<TableCell align="left"> {this.state.persons.map((items,name) =>
<div key={this.state.persons.id} >{(typeof(items.dish_count)=="object")? (<div>
{
items.dish_count.map((subdata) =>
<table>
<td >
{subdata.dish_count}
</td>
</table>
)
}
</div>): (null)}</div>)}</TableCell>
i want to map subarray dish_count by key id of parent array .I am able to map but the mapping is multiple and is not exclusive by parent array key.dish_count is the subarray of package array
persons array
"data": [
{
"id": 1,
"name": "Gold",
"dish_count": [
{
"dish_count": 4,
"meal_type": "Starters"
},
{
"dish_count": 4,
"meal_type": "Main Course"
},
{
"dish_count": 4,
"meal_type": "Dessert"
},
{
"dish_count": 4,
"meal_type": "Lunch"
}
]
},
{
"id": 2,
"name": "Basic",
"dish_count": [
{
"dish_count": 2,
"meal_type": "Starters"
},
{
"dish_count": 2,
"meal_type": "Main Course"
},
{
"dish_count": 2,
"meal_type": "Dessert"
},
{
"dish_count": 2,
"meal_type": "Lunch"
}
]
}
]
I want
Meal Type No of Dishes
Gold Starters 4
Main Course 4
Desert 4
Lunch 4
Basic Starters 2
Main Course 2
Desert 2
Lunch 2

You have a few problems in your code:
this.state({persons:''});: This will set the initial persons to be an empty string and will fail with map.
console.log('package',this.state.persons): setState is async and the console.log will not print the desired state but the previous state. Use the callback of setState as second parameter to access the new state:
this.setState({persons:res.data.data.data}, () => console.log('package',this.state.persons) );
this.state.persons.map((items, name) =>: The map function will provide different parameters: the first is the person and the second is the index of that person within the array.
div key = {this.state.persons.id}: since persons is an array, the key will be undefined. If you use the map function correctly, you can use person.id.
When you fixed these problems, the code should work as expected.
To only show the expected dishes per person and not to print the duplication you have to write it like this:
class Table extends React.Component {
render() {
return <table>
<thead>
<tr>
<td>ID</td>
<td>Name</td>
<td>Meal Type</td>
<td>Number of Dishes</td>
</tr>
</thead>
<tbody>
{this.state.persons.map(person =>
<tr>
<td>{person.id}</td>
<td>{person.name}</td>
<td>
<table>
<tbody>
{person.dish_count.map(dish => <tr>
<td>{dish.meal_type}</td>
</tr>
)}
</tbody>
</table>
</td>
<td>
<table>
<tbody>
{person.dish_count.map(dish => <tr >
<td>{dish.dish_count}</td>
</tr>
)}
</tbody>
</table>
</td>
</tr>
)
}
</tbody>
</table >
}
}
By not iterating over the person for each sub-table, you can remove the duplicated data.
codepen
Hope this helps.

Related

Mappin over an array of objects to display it in React

I am learning React, and I been stuck here for a while now, the Middle.js component and table. I am trying to loop over array of objects from the data I am fetching. It is userPools array and display in a table poolProvidersname and then consequently rest of the data.
I am quite confused as to how do I do this?
Here is the the sandbox: https://codesandbox.io/s/naughty-ellis-xrir4?file=/src/components/Table.js
Thank you.
jumping from JS to markup on JSX can bit a bit confusing at first
When iterating an array of objects for display purposes, what you want to do is return a JSX fragment for each item on your array.
So if you have an array that looks like this:
var data = [{ id: 1, name: 'Lucia', age: 20 }, { id: 2, name: 'Karina', age: 21 }, { id: 3, name: 'Maria', age: 22 }];
to display it in your component you would go like this:
const Table = ({ data }) => {
if (!Array.isArray(data)) return null;
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
{
data.map(item => // notice how we jump straight back to JSX here
<tr key={item.id}>
<td>
{item.name}
</td>
<td>
{item.age}
</td>
</tr>)
}
</tbody>
</table>
);
};

How do I display an array where each object in array is a new <td> in ReactJS

I have an array which contains multiple objects like this:
const locations = [
{
information: ["Data Analyst", "Uruguay", "Montevideo", "$30,000"],
},
{
information: ["CTO", "UK", "Manchester", "$75,000"],
}
];
And I want to display each array in a new table row containing a <td> with each string.
Currently I have done this:
<tr>
{locations.map((location) => <td>{location.information}</td>)};
</tr>
Which returns each piece of information on a <td>
This is how the data looks at the minute:
And how it's meant to look
For this you have to use Array.map() like:
// To create tha table body by iterating data array
{
locations.map((location, locationIndex) =>
<tr key={locationIndex}>
<td>{location.information[0]}</td>
<td>{location.information[1]}</td>
<td>{location.information[2]}</td>
<td>{location.information[3]}</td>
</tr>
)
}
// In case you don't want to harcode the array index
{
locations.map((location, locationIndex) =>
<tr key={locationIndex}>
location.information.map((loc, locIndex) =>
<td key={locIndex}>{loc}</td>
)
</tr>
)
}
Change the code from,
<tr>
{locations.map((location) => <td>{location.information}</td>)};
</tr>
To:
<table border="1" width="100%" className="component_useRefBox">
<tbody>
{locations.map((location, i) => {
return (
<tr key={i}>
{location.information.map((data, j) => {
return <td key={j}> {data} </td>;
})}
</tr>
);
})}
</tbody>
</table>
To display two records row by row, you need to move {locations.map((location) .... )} above <tr> ... </tr> tag, because while using map method only each row will get iterated and you will get two separate rows..
{locations.map((location, i) => {
return (
<tr>
....
</tr>
)})}
As location.information is of array data, you cannot assign it directly.
You need to iterate using map and display each data like,
{location.information.map((data) => {
return <td> {data} </td>;
})}

react hooks toggle for specific row

Please clarify my problem of toggle for specific row of the table with react hooks. whenever I press click.. it opens for every row and by default the table head is moving right it is not constant.
Error in toggleHidden(key). How to correct my toggleHidden function?
const[isHidden , setIsHidden] = React.useState(true)
const toggleHidden = () => setIsHidden(!isHidden)
const data = [
{
"name": "gvf",
"email": "abc",
"companyname": "xyz",
"address": "abcy"
},
{
"name": "abi",
"email": "dhf",
"companyname": "dhd",
"address": "fhfh"
}
]
return (
<div>
<Row>
<Col>
<table className="table table-hover table-striped table-sm">
<thead className="thead-dark">
<tr>
<th>Name</th>
<th>Email</th>
<th>CompanyName</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{data.map((a , key) => (
<tr key={a.name}>
<td><Button onClick = {toggleHidden(key)}>Click</Button>
{!isHidden && <p>Hello ABIII</p> }
</td>
<td>{a.name}</td>
<td>{a.email}</td>
<td>{a.address}</td>
<td>{a.companyname}</td>
</tr>
))}
</tbody>
</table>
</Col>
</Row> </div>
you need define the specific row - when You mapping:
{data.map(a => (
)}
try add key attribute to every item in collection like this:
{data.map((a, key) => (
))}
then pass to Your item:
<tr key={key}>
So now every is unique - so if You pass that key to your function:
<Button onClick = {toggleHidden(key)}>
the program should know which specific item execute toggleHidden function

React map array inside serialized DRF with a manytomanyfield relation and StringRelatedField

From my Django DRF serializer, I'm trying to map an array with an object in React.
serializer.py
class AssessmentSerializer(serializers.ModelSerializer):
objective = serializers.StringRelatedField(
many=True,
)
class Meta:
model = Assessment
fields = ['id', 'name', 'date_completed', 'objective']
The state from DRF looks ok:
{
grades: {
grades: [
{
id: 7,
name: 'Quiz 4',
date_completed: '2020-03-17',
objective: [
"kin.2",
"kin.1"
]
}
]
}
}
But I'm trying to separate out the kin.2 and kin.1 in my JSX table:
<tbody>
{this.props.grades.map(grade => (
<tr key={grade.id}>
<td>{grade.id}</td>
<td>{grade.name}</td>
<td>{grade.date_completed}</td>
<td>
<ul>
<li>{grade.objective}</li>
</ul>
</td>
</tr>
))}
</tbody>
Currently the 'kin.1' and 'kin.2' are printing on the same line with no space between the text. I've also tried:
<tbody>
{this.props.grades.map(grade => (
<tr key={grade.id}>
<td>{grade.id}</td>
<td>{grade.name}</td>
<td>{grade.date_completed}</td>
<td>
<ul>
{grade.objective.map(obj => (
<li>{obj.objective}</li>
))}
</ul>
</td>
</tr>
))}
</tbody>
This comes close, the list is empty although it iterates the correct number of times. Do I have to serialize some type of index with the 'objective'?
grade.objective is a list, so obj.objective wont work. Instead use obj
<tbody>
{this.props.grades.map(grade => (
<tr key={grade.id}>
<td>{grade.id}</td>
<td>{grade.name}</td>
<td>{grade.date_completed}</td>
<td>
<ul>
{grade.objective.map(obj => (
<li>{obj}</li>
))}
</ul>
</td>
</tr>
))}
</tbody>

Smart Table search not working when creating multiple tables

This is what I am doing.
I call a rest api which returns response in this format
"metalanguages": {
"1": {
"id": 1,
"name": "Abkhaz"
},
"2": {
"id": 2,
"name": "Afar"
}
},
"manufacturers": {
"-1": {
"id": -1,
"name": "all"
},
"1": {
"id": 1,
"name": "RIM"
},
"2": {
"id": 2,
"name": "HP"
}
}
This is basically a Map of String and Map.
I now have to create n number of table where n is number of keys of original map and inside each table I have to show data which will be the value of internal map ("id": 2,
"name": "HP")
I have made it working but search is not working.
This is my sample code
<div ng-repeat="(key,value) in metadataDetails">
<table st-table="metadataCollection" st-safe-src="metadataDetails" class="table table-striped">
<thead>
<tr class="style_tr">
<th st-sort="name">name</th>
<th st-sort="name">name</th>
<th st-sort="description">description</th>
<th st-sort="countryName">countryName</th>
<th st-sort="carrierName">carrierName</th>
</tr>
<tr class="textSearchTr">
<th colspan="4" class="textSearchTr">
<input class="freshblue" placeholder="Enter value to search/filter" type="text" ng-model="searchParam.search" />
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in getValueMap(key)" ng-show="showRow">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.description}}</td>
</tr>
</tbody>
</table>
</div>
And my js file
AuditMetadataService.get({}, function(data) {
$scope.numRecord = data.length;
$scope.metadataDetails = data;
$scope.metadataCollection = [].concat($scope.metadataDetails);
console.log("Return value :");
console.log($scope.metadataDetails);
});
$scope.getValueMap = function(key) {
console.log(key);
return $scope.metadataDetails[key];
};
Could someone please help??
You can turn your map object into an array by getting it's keys and using the Array.prototype.map function, you will have to repeat this for the inner map objects as well because st-sort expects an array item, not a key value.
$scope.tables = keys.map(function(key) {
return Object.keys(data[key]).map(function(k) {
return data[key][k];
});
});
Then you can iterate $scope.tables using ng-repeat to create all the tables want, clicking the column titles will now sort them properly.
Here is a demo.

Resources