How to call nested object list on table list - reactjs

Hi im newbie on react js,
how to call nested object(array/list) on main object, i mean object in object
<tbody>
{
vehicles.map((v, index) =>(
<tr key={v.id}>
<td>{index +1}</td>
<td>{v.type}</td>
<td>{v.plateNumber}</td>
{v.employee.map(item => {
return (
<td>
<ul>{item.name}</ul>
</td>
);
})}
<td>
<Link className="btn btn-info" to={`/vehicles/edit/${v.id}`}>Update</Link>
<button className="btn btn-danger ml-2" onClick={() => {deleteSweetAlert(v.id)}}>Delete</button>
</td>
</tr>
))
}
</tbody>
This one my JSON example
[
{
"id": 1,
"type": "MasterCard",
"plateNumber": "3747948",
"status": "1",
"employee": {
"id": 1,
"name": "Joanne Hagenes Sr.",
"location": "60794 Rippin Cove Suite 080\nTroyberg, ND 95778",
"department": "Wuckert-Luettgen",
"status": "1"
}
}
]
I always get this error message at the console
react-dom.development.js:26874 Uncaught TypeError: v.employee.map is not a function

map() function can only applied with an array, so in your case employee should be an array instead an object:
{
"id": 1,
"type": "MasterCard",
"plateNumber": "3747948",
"status": "1",
"employee": [{
"id": 1,
"name": "Joanne Hagenes Sr.",
"location": "60794 Rippin Cove Suite 080\nTroyberg, ND 95778",
"department": "Wuckert-Luettgen",
"status": "1"
}]
}
Another way to fix this, since each of your vehicle contains only 1 employee (based on how u named it). So i suppose you dont need to use map() function in this case:
<tbody>
{
vehicles.map((v, index) =>(
<tr key={v.id}>
<td>{index +1}</td>
<td>{v.type}</td>
<td>{v.plateNumber}</td>
<td>
<ul>{item.name}</ul>
</td>
<td>
<Link className="btn btn-info" to={`/vehicles/edit/${v.id}`}>Update</Link>
<button className="btn btn-danger ml-2" onClick={() => {deleteSweetAlert(v.id)}}>Delete</button>
</td>
</tr>
))
}
</tbody>

You can use interface to define.
interface IFoo {
foo: string;
}
interface IBaz {
baz: string;
foo: IFoo;
}
const obj: IBaz = {
baz: 'bar',
foo: {
foo: 'foo',
},
};
console.log(obj.baz); // -> baz
console.log(obj.foo.foo); // -> foo

Related

How to run map inside map function in Reactjs

I want my axios part should run first inside useEffect so that my state can be update first and then further I can use that.
Here is error:
TypeError: Cannot read property map of undefined
When I console it shows states is not updated it holds SwitchCOM empty array
That means it directly goes for the return statement without running useEffect axios part.
This is what my SwitchCom state look like:
SwitchCOM: {
0: {id: "36", name: "XYZ", progress: "", details: [{id: "36", name: "XYZ", progress: ""}]},
1: {id: "83", name: "ABC", progress: "", details: [{id: "36", name: "XYZ", progress: ""}]},
2: {id: "77", name: "EFG", progress: "", details: [{id: "36", name: "XYZ", progress: "" }]}
}
const initialState = {
SwitchCOM: [],
isFetching: false,
hasError: false
}
{states.SwitchCOM.map(topis => (
<div className="item" key={topis.id}>
<p>{topis.name}</p>
<p>
<progress id="file" value="32" max="100">
{topis.progress}
</progress>
</p>
{topis.activities.map(activity => (
<table key={activity.id}>
<tbody>
<tr>
<td>Name</td>
<td>Progress</td>
<td>Status</td>
</tr>
<tr >
<td>{activity.name}</td>
<td>{activity.prog}</td>
</tr>
</tbody>
</table>
))}
</div>
))}
You are trying to map through an object which won't work. Instead you need to use Object.keys(...) to accomplish what you want here.
You should do something like this:
{Object.keys(states.SwitchCOM).map(key => (
<div className="item" key={states.SwitchCOM[key].id}>
<p>{states.SwitchCOM[key].name}</p>
<p>
<progress id="file" value="32" max="100">
{states.SwitchCOM[key].progress}
</progress>
</p>
{states.SwitchCOM[key].details.map(detail => (
<table key={detail.id}>
<tbody>
<tr>
<td>Name</td>
<td>Progress</td>
</tr>
<tr>
<td>{detail.name}</td>
<td>{detail.progress}</td>
</tr>
</tbody>
</table>
))}
</div>
))}

how to map subarray by key of parent array 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.

Mapping an array in react, descending order

I want to use the following data
[
{
"id": "1",
"label": "Score",
"tabledata": [
{"label": "Day 1", "data": {"score": 73}},
{"label": "Day 2", "data": {"score": 64}},
{"label": "Day 3", "data": {"score": 72}}
]
}, {
"id": "2",
"label": "Success",
"tabledata": [
{"label": "Day 1", "data": {"score": 73 }},
{"label": "Day 2", "data": {"score": 64 }},
{"label": "Day 3", "data": {"score": 72}}
]
} ]
<table>
<tr>
<td>
</td>
<td>
Score
</td>
<td>
Success
</td>
</tr>
<tr>
<td>
Day 3
</td>
<td>
72
</td>
<td>
72
</td>
</tr>
<tr>
<td>
Day 2
</td>
<td>
64
</td>
<td>
64
</td>
</tr>
<tr>
<td>
Day 1
</td>
<td>
73
</td>
<td>
73
</td>
</tr>
</table>
The solution i came up is:
<table >
<tr>
<td> </td>
<td>
{this.props.GraphData[0].label}
</td>
<td>
{this.props.GraphData[1].label}
</td>
</tr>
<tr>
<td> </td>
<td>
{this.props.GraphData[0].tabledata.data.map(row => ([ <tr key={i}> <td> {row.score}</td> </tr> )])};
</td>
<td>
{this.props.GraphData[1].tabledata.data.map(row => ([ <tr key={i}> <td> {row.score}</td> </tr> )])};
</td>
</tr>
</table>
How can I turn with reverse.map the values to appear in descending order (the first row (day 3) and last row (day 1).
Finally is there a way to avoid using [0] or [1] from the data file but to use mapping for all the rows and columns of the table?
first of all, your data structure is adding complexity as hell, and i advice you to structure it well so you could easily consume it, I've made a refactoring for your code and also restructured your data with a generic way so even day4, ...dayn could be shown, that shows well how complex the consumption became if we think generically, so this is what I've got, so rename this file as Table.jsx and try to import it as so import Table from './Table';:
import React from 'react';
import { get, map, reduce, uniq, find, orderBy } from 'lodash';
const data = [
{
id: '1',
label: 'Score',
tabledata: [
{ label: 'Day 1', data: { score: 73 } },
{ label: 'Day 2', data: { score: 64 } },
{ label: 'Day 3', data: { score: 72 } },
{ label: 'Day 5', data: { score: 60 } }
]
},
{
id: '2',
label: 'Success',
tabledata: [
{ label: 'Day 1', data: { score: 73 } },
{ label: 'Day 2', data: { score: 64 } },
{ label: 'Day 3', data: { score: 73 } }
]
}
];
const columnsHeaders = ['day', ...map(data, 'label')];
const days = uniq(
reduce(
data,
(acc, item) => [...acc, ...map(get(item, 'tabledata'), 'label')],
[]
)
);
const restructuredData = reduce(
days,
(acc, day) => {
const dayData = reduce(
map(data, 'label'),
(dayDataAcc, colName) => {
return {
...dayDataAcc,
day,
[colName]: get(
find(get(find(data, { label: colName }), 'tabledata'), {
label: day
}),
['data', 'score']
)
};
},
{}
);
return [...acc, dayData];
},
[]
);
const sortedData = orderBy(restructuredData, 'day', 'desc');
const TableHeaders = () => (
<thead>
<tr>{map(columnsHeaders, (col, index) => <th key={index}>{col}</th>)}</tr>
</thead>
);
// checking our data
console.log('restructuredData', restructuredData);
console.log('sortedData', sortedData);
const TableRows = ({ data }) => (
<tbody>
{map(data, ({ day, Score: score, Success: success }) => (
<tr key={day}>
<td>{day || '-'}</td>
<td>{score || '-'}</td>
<td>{success || '-'}</td>
</tr>
))}
</tbody>
);
export default () => (
<table>
<TableHeaders />
<TableRows data={sortedData} />
</table>
);

How to make sub table <tr> of parent table <tr>?

I know that maybe this question can be confusing for you, but I will try to explain in more detail.
First: I have this api
{
"data": [
{
"id": 1,
"title": "Действие 1",
"subactions": [
{
"id": 2,
"title": "Субдействие 1",
"status": {
"id": 1,
"text": "Выполнено"
},
"countries": [
"kz",
"kg"
],
"theme": {
"id": 1,
"text": "Изменение климата"
},
"characteristics": {
"0": "Другие действия",
"id": 1
},
"monthes": [
{
"month": 1,
"year": 2017,
"complete": 0
},
{
"month": 2,
"year": 2017,
"complete": 1
},
{
"month": 3,
"year": 2017,
"complete": 1
},
{
"month": 4,
"year": 2017,
"complete": 1
},
{
"month": 5,
"year": 2017,
"complete": 1
},
{
"month": 1,
"year": 2018,
"complete": 0
},
{
"month": 2,
"year": 2018,
"complete": 0
}
]
}
]
}
The second: the table should look like in this picture
The third: The problem is that I don not know how to loop <tr> as child of another <tr> parent.
The Fourth: This my attempts of doing that
{
task.map((value, i) => {
if(value.subactions !== undefined){
return (
value.subactions.map((subaction, i) => {
return (
<div>
{/*Parent tr*/}
<tr key={i}>
<td>{value.id}</td>
<td>{value.title}</td>
</tr>
{/* end Parent tr*/}
{/*sub table of parent tr*/}
<tr key={i}>
<td>{subaction.id}</td>
<td>{subaction.title}</td>
<td>{subaction.status.text}</td>
<td>
{subaction.countries.map((country, i) => {
return (
i == subaction.countries.length - 1 ?
<span key={i}>{country} </span> :
<span key={i}> {country},</span>
)
})
}
</td>
<td></td>
<td>{subaction.theme.text}</td>
<td>{subaction.characteristics[0]}</td>
{subaction.monthes.map((month, i) => {
return (
month.complete ?
<td className='task-month task-end'>
<input
type="checkbox"
className="css-checkbox lrg"/>
<label htmlFor="checkbox69" name="checkbox69_lbl"
className="css-label lrg vlad"/>
</td> : <td></td>
)
})
}
</tr>
{/*end sub table of parent tr*/}
</div>
)
})
)
} else {
return undefined
}
})
}
Please, anyone help to point out of my mistakes.
Replace div tag to table tag and In you parent table at second td use colspan="(total number of td in your second tr) - 2"
check below changes , I have mentioned the colspan count :
task.map((value, i) => {
if(value.subactions !== undefined){
return (
value.subactions.map((subaction, i) => {
return (
<table>
{/*Parent tr*/}
<tr key={i}>
<td>{value.id}</td>
<td colspan="1+totalContriesCount+2+totalMonthsCount">{value.title}</td>
</tr>
{/* end Parent tr*/}
{/*sub table of parent tr*/}
<tr key={i}>
<td>{subaction.id}</td>
<td>{subaction.title}</td>
<td>{subaction.status.text}</td>
<td>
{subaction.countries.map((country, i) => {
return (
i == subaction.countries.length - 1 ?
<span key={i}>{country} </span> :
<span key={i}> {country},</span>
)
})
}
</td>
<td></td>
<td>{subaction.theme.text}</td>
<td>{subaction.characteristics[0]}</td>
{subaction.monthes.map((month, i) => {
return (
month.complete ?
<td className='task-month task-end'>
<input
type="checkbox"
className="css-checkbox lrg"/>
<label htmlFor="checkbox69" name="checkbox69_lbl"
className="css-label lrg vlad"/>
</td> : <td></td>
)
})
}
</tr>
{/*end sub table of parent tr*/}
</table>
)
})
)
} else {
return undefined
}
})
}
Try making the parent row span to the maximum so you might achieve the output
<tr>
<td rowspan="maxRowCount"></td>
<td colspan="1"></td>
</tr>

Angularjs: how to replace , with line break<br> in angular filter

My doubt is simple. How to replace , with line break in angular filter. i also added the demo jsfFiddle
angular
.module('myApp', [])
.filter('nicelist', function() {
return function(input) {
if (input instanceof Array) {
return input.join(",");
}
return input;
}
})
.controller('ctrl', function($scope) {
$scope.todolists = [{
"id": "id_584",
"customer_id": 2,
"url": "url",
"bill_number": "123",
"location": "from_location"
}, {
"id": "id_122",
"customer_id": 3,
"url": "url",
"bill_number": "123",
"location": "from_location"
}, {
"id": "id_128",
"customer_id": 4,
"url": "url",
"bill_number": "123",
"location": "from_location"
}, {
"id": "id_805",
"customer_id": 5,
"url": "url",
"bill_number": "123",
"location": "from_location"
}, {
"id": "id_588",
"customer_id": 6,
"url": "url",
"bill_number": "123",
"location": "from_location"
}, {
"id": ["id_115"," id_114"],
"customer_id": 7,
"url": "url",
"bill_number": "123",
"location": "from_location"
}]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp" ng-controller="ctrl">
<table class="table table-hover tr-table transactions" style="width: 100%;">
<thead>
<tr class="search-row pending-orders table-header-row-height tr-table-head">
<th>ID</th>
<th>Bill Number</th>
<th>Location</th>
<th>Url</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="todolist in todolists">
<td>{{todolist.id | nicelist }}</td>
<td>{{todolist.bill_number}}</td>
<td>{{todolist.location}}</td>
<td><a target="_blank" href="{{ 'http://' + todolist.url}}">Download Invoice : <i title="Download Invoice" style="padding-left:5px;cursor:pointer;color:black;" class="fa fa-download"></i></a> </td>
</tr>
</tbody>
</table>
</body>
demo
In the above link, there will be table. In ID column last row contain 2 values which is present in array inside the json. Now instead of comma(,) is there any possible way for line break.
Please share your knowledge.
you use ng-bind-html with injecting sanitize at module level .
html:
<tbody>
<tr ng-repeat="todolist in todolists">
<td ng-bind-html="todolist.id | nicelist"></td>
<td>{{todolist.bill_number}}</td>
<td>{{todolist.location}}</td>
<td><a target="_blank" href="{{ 'http://' + todolist.url}}">Download Invoice : <i title="Download Invoice" style="padding-left:5px;cursor:pointer;color:black;" class="fa fa-download"></i></a> </td>
</tr>
</tbody>
code:
angular.module('myApp', ['ngSanitize']) //Inject here
.filter('nicelist', function() {
return function(input) {
if (input instanceof Array) {
return input.join("<br>");
}
return input;
}
})
working sample up for grabs here.
ng-bind-html directive Documentation
PS: make sure you inject sanitize or you can use different techiques .

Resources