Mapping an array of each object in array in React - javascript

I've got a data.json file with an array of group objects, and each group object contains products array, like:
[
{
"groupId": int
"familyId": int,
"products": array (lenght of 10-50)
}
{
"groupId": int
"familyId": int,
"products": array (lenght of 10-50)
}, and so on...
]
I would like to map them like:
<ul> GroupId
<li>Product 1</li>
<li>Product 2</li>
<ul/>
<ul>
GroupId
<li>Product 1</li>
<li>Product 2</li>
</ul>
etc.
I've tried to use foreach function and then map every array but it doesn't work.
import data from '../data.json';
let productsList = [];
{data.forEach((el) => {productsList.push(el.products)})}
{productsList.forEach((array) => {
array.map((el) => {
return (
<ul>
<li>{el.name}</li>
</ul>
)
})
})}

I recommend you solve this with simple react components, it will make your code more readable.
I created a simple example to solve your issue
export default function App() {
const data = [
{
groupId: 1,
familyId: 1,
products: [
{ id: 1, name: "product 1", price: 10 },
{ id: 2, name: "product 2", price: 20 }
]
},
{
groupId: 2,
familyId: 2,
products: [{ id: 3, name: "product 3", price: 30 }]
}
];
return (
<div className="App">
{data.map((group) => (
<ProductGroup group={group} />
))}
</div>
);
}
ProductGroup Component
const ProductGroup = ({ group }) => {
return (
<>
<ul>{group.groupId}</ul>
{group.products.map((product) => (
<ProductItem product={product} />
))}
</>
);
};
ProductItem Component
const ProductItem = ({ product }) => {
return (
<li>
<span>{product.name}</span>
<span style={{ marginLeft: "10px" }}>{product.price}$</span>
</li>
);
};

Try this one
const listItems = () => (
<>
{array.map((group) => (
<ul key={group.groupId}>
{group.groupId}
{group.products.map((productList, index) => (
<li key={index}>{productList}</li>
))}
</ul>
))}
</>
);

Related

Data object with array of different groups, trying to display ordered by group type using .map() and pushing to new array nothing is rendering

I have a React Component I'm building out that accepts a data object as props.
This data object holds an array of groups each with it's own group type.
What I'm trying to do is map over each group in the array and display it's contents as it's own section, but I also want to ensure that all of the objects with the type grid display together, followed by any sections with a list type no matter what position they are in the array.
So even if the array holds the values like:
[{Grid}, {List}, {Grid}, {List}, {Grid}]
It will display like this:
Group #1 (Grid)
Contents
Group #2 (Grid)
Contents
Group #3 (Grid)
Contents
Group #4 (List)
Contents
Group #5 (List)
Contents
The problem I'm having is that I wrote two separate components to handle the styling of each type and then passed them into a function that creates a new array from the original to then render, and nothing is displaying. I'm not getting any error messages or anything in the console so I'm completely stumped as to where I'm going wrong.
Here are my components, the data structure and a Codesandbox:
// Component File
import "./styles.css";
import data from "./resourceMock";
import FileIcon from "./FileIcon";
const GridView = (group) => {
const { groupName, items } = group;
return (
<>
<h2>{groupName}</h2>
<ul
style={{
display: "inline-flex",
flexWrap: "wrap",
listStyleType: "none"
}}
>
{items.map((item) => {
return (
<li style={{ height: "40vh", flexGrow: 1 }}>
<img src={item.img} style={{ height: "150px", width: "150px" }} />
<h4>{item.name}</h4>
<h5>{item.subtitle}</h5>
</li>
);
})}
</ul>
</>
);
};
const ListView = (group) => {
const { groupName, items } = group;
return (
<>
<h2>{groupName}</h2>
<ul style={{ listStyleType: "none" }}>
{items.map((item) => {
return (
<li>
<FileIcon />
{item.title}
</li>
);
})}
</ul>
</>
);
};
function renderList(group) {
const lists = [];
if (!group) return null;
data.map((group) => {
switch (group.groupType) {
case "grid":
return lists.push((group) => {
<GridView group={group} />;
});
case "list":
return lists.push((group) => {
<ListView group={group} />;
});
default:
return lists.push((group) => {
<ListView group={group} />;
});
}
});
return lists;
}
export default function App() {
return <div className="App">{data.map((group) => renderList(group))}</div>;
}
Data Structure:
export default [
{
groupName: "Marvel Characters",
groupType: "grid",
items: [
{
name: "Iron Man",
subtitle: "Inventor Tony Stark",
img:
"https://www.denofgeek.com/wp-content/uploads/2019/02/mcu-1-iron-man.jpg?resize=768%2C432"
},
{
name: "Incredible Hulk",
subtitle: "Bruce Banner",
img:
"https://lh3.googleusercontent.com/proxy/-jHnFcGLqlxjdOl9Mf99UPBk4XJKcQ1Hsv7lPYEs8Vai874sW0l5TUwn3acriwGpE36aUDPpZHPFzccRUt7b7POGOWCFIbgYomTO9bDCXF0eovxFGdr_D3P-0wfLnkUMOOJDG09MgAzqSCbiDq-A"
}
]
},
{
groupName: "Magic Cards",
groupType: "list",
items: [
{
title: "Kamahl, Fist Of Krosa",
link:
"https://gatherer.wizards.com/pages/card/Details.aspx?multiverseid=220490"
},
{
title: "Seedborn Muse",
link:
"https://gatherer.wizards.com/pages/card/Details.aspx?multiverseid=446180"
}
]
},
{
groupName: "DC Characters",
groupType: "grid",
items: [
{
name: "Batman",
subtitle: "Bruce Wayne",
img:
"https://static.wikia.nocookie.net/marvel_dc/images/a/a6/Batman_Vol_2_2_Variant_Textless.jpg/revision/latest/top-crop/width/360/height/450?cb=20120228075313"
},
{
name: "Martian Manhunter",
subtitle: "J'onn J'onzz",
img:
"https://cdn.flickeringmyth.com/wp-content/uploads/2021/03/Martian-Manhunter-600x338.png"
}
]
},
{
groupName: "Kaiju and Mechs",
groupType: "grid",
items: [
{
name: "Godzilla",
img:
"https://www.denofgeek.com/wp-content/uploads/2019/05/godzillakingofmonsters-2.jpg?resize=768%2C432"
},
{
name: "Hunter Vertigo",
img: "https://i.ytimg.com/vi/7F-iZYAqSbw/maxresdefault.jpg"
}
]
},
{
groupName: "Comic Books",
groupType: "list",
items: [
{
title: "Descender",
link: "https://imagecomics.com/comics/series/descender"
},
{
title: "East of West",
link: "https://imagecomics.com/comics/series/east-of-west"
},
{
title: "Letter 44",
link: "https://onipress.com/collections/letter-44"
}
]
}
];
I have fixed the issues.
Sandbox: https://codesandbox.io/s/affectionate-sinoussi-5suro
You are already looping over data inside renderList, so we can directly have <div className="App">{renderList(data)}</div>;
To sort, we can use Array.sort()
data.sort((a, b) => a.groupType === b.groupType ? 0 : a.groupType > b.groupType ? 1 : -1);
Also, in switch case you need to push the component and not a function.
case "grid":
lists.push(<GridView group={group} />);
break;
Need to use destructuring here const ListView = ({ group }) => {}
Finally add key to your lists. I have added using the item name, but you need to change per your requirement.

Recursive function in Reactjs

I am making dynamic menus using a recursive function and I have already made the menus and it display in the right order without any issues.
And I receive the data for menu from service.js file and you can see the entire working application in the below code sandbox example,
https://codesandbox.io/s/reactstrap-accordion-3uoz9
Requirement:
Here I am in the need to find out the last level of menus and need to assign checkbox with value as their respective id {item.id}.
Eg:
For First menu one,
-> [Checkbox with value as 1.1.1] One-One-One
-> [Checkbox with value as 1.1.2] One - one - two
-> [Checkbox with value as 1.1.3] One - one - three
For Second menu two,
-> [Checkbox with value as 2.1] Two - one
.
.
.
For sixth menu six,
-> [Checkbox with value as 6] Six
I hope the point is clear that I need to find out the last level in recursion and should assign a checkbox to it with the value of their id.
Please fork the code sandbox provided and help me to achieve the result of making the checkbox at the last level.
Optional requirement:
The collapse is working for whole menus at once if possible please make it collapse at each individual level in unique.
But the main important requirement is to make a checkbox at the last level of menus.
A big thanks in advance...
Edit:
As commented by Crowder, I have created the snippet removing reactstrap code and it is okay now because I am in the need of displaying checkbox inline to laste level of submenus (last children elements).
const menuData = [
{
id: "1",
name: "One",
children: [
{
id: "1.1",
name: "One - one",
children: [
{ id: "1.1.1", name: "One - one - one" },
{ id: "1.1.2", name: "One - one - two" },
{ id: "1.1.3", name: "One - one - three" }
]
}
]
},
{
id: "2",
name: "Two",
children: [{ id: "2.1", name: "Two - one" }]
},
{
id: "3",
name: "Three",
children: [
{
id: "3.1",
name: "Three - one",
children: [
{
id: "3.1.1",
name: "Three - one - one",
children: [
{
id: "3.1.1.1",
name: "Three - one - one - one",
children: [
{ id: "3.1.1.1.1", name: "Three - one - one - one - one" }
]
}
]
}
]
}
]
},
{ id: "4", name: "Four" },
{
id: "5",
name: "Five",
children: [
{ id: "5.1", name: "Five - one" },
{ id: "5.2", name: "Five - two" },
{ id: "5.3", name: "Five - three" },
{ id: "5.4", name: "Five - four" }
]
},
{ id: "6", name: "Six" }
];
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
currentSelection: "",
menuItems: [],
isToggleOpen: false
};
}
componentDidMount() {
this.setState({ menuItems: menuData });
}
handleClick(id, evt) {
evt.preventDefault();
console.log("click handler called with", id);
this.setState({ currentSelection: id });
}
toggle() {
console.log(this.state);
this.setState({
isToggleOpen: !this.state.isToggleOpen
});
}
buildMenu(items) {
return (
<ul>
{items &&
items.map(item => (
<li key={item.id}>
<div>
{item.name}
{item.children && item.children.length > 0
? this.buildMenu(item.children)
: null}
</div>
</li>
))}
</ul>
);
}
render() {
return (
<div>
<h2>Click any of the below option</h2>
{this.state.menuItems &&
this.state.menuItems.map((item, index) => {
return (
<div key={index}>
{item.name}
{this.buildMenu(item.children)}
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/reactstrap/4.8.0/reactstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/reactstrap/4.8.0/reactstrap.min.css" />
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.development.js"></script>
buildMenu(items) {
return (
<ul>
{items &&
items.map((item, index) => (
<li key={item.id}>
<div>
{this.state.isToggleOpen}
{(item.children) ? 'Not Last': 'Here you can apply your check box'} //this check if item have children
<Button onClick={this.toggle.bind(this)}> {item.name} {index} </Button>
<Collapse isOpen={this.state.isToggleOpen}>
{item.children && item.children.length > 0
? this.buildMenu(item.children, index)
: null}
</Collapse>
</div>
</li>
))}
</ul>
);
}
Now second case on render
<Button onClick={this.toggle.bind(this)}> {item.name}</Button>
Check if item have children
{(item.children) ? this.buildMenu(item.children) : 'Apply your checkbox here'}
Full Code
import React from "react";
import { render } from "react-dom";
import { loadMenu } from "./service";
import { Button, Collapse } from "reactstrap";
// const buildMenu = function buildMenu(items)
// const Menu = ({ items }) => buildMenu(items);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
currentSelection: "",
menuItems: [],
isToggleOpen: false
};
}
componentDidMount() {
loadMenu().then(items => this.setState({ menuItems: items }));
}
handleClick(id, evt) {
evt.preventDefault();
console.log("click handler called with", id);
this.setState({ currentSelection: id });
}
toggle() {
console.log(this.state);
this.setState({
isToggleOpen: !this.state.isToggleOpen
});
}
buildMenu(items) {
return (
<ul>
{items &&
items.map(item => (
<li key={item.id}>
<div>
{this.state.isToggleOpen}
{(item.children) ? 'Not Last': 'Here you can apply your check box'}
<Button onClick={this.toggle.bind(this)}> {item.name} </Button>
<Collapse isOpen={this.state.isToggleOpen}>
{item.children && item.children.length > 0
? this.buildMenu(item.children)
: null}
</Collapse>
</div>
</li>
))}
</ul>
);
}
render() {
console.log(this.state.menuItems);
return (
<div>
<h2>Click any of the below option</h2>
{this.state.menuItems &&
this.state.menuItems.map((item, index) => {
return (
<div>
<Button onClick={this.toggle.bind(this)}> {item.name} </Button>
{(item.children) ? 'Not Last': 'Here you can apply your check box'}
<Collapse isOpen={this.state.isToggleOpen}>
{this.buildMenu(item.children)}
</Collapse>
</div>
);
})}
</div>
);
}
}
render(<App />, document.getElementById("root"));

read an array of objects in array of object

I have a problem to map an array of objects in an array of objects...
this is my array in back
const demoCompletedData = [
{
id: 1,
marketId: "1111-1111-1111-1111",
title: "Autonomous car",
picture: "https://th?id=OIP.fdvfdvfdvfdvfd&pid=Api",
language: "English",
flag: "🇬🇧",
completed: true,
date: "22/01/2019 10:30",
rate: 9.1,
categories: {
de: 1,
sp: 2,
uk: 0,
fr: 1,
us: 4,
},
},
module.exports = demoCompletedData;
And my code to read this in front :
fetchDemo
fetchDemo() {
this.props.demoFetchRequest();
const { marketId } = this.props.match.params;
axios.get(`/api/v1/passport-authenticate/market/${marketId}`)
.then((res) => {
return res.data;
})
.then(demo => this.props.demoFetchSuccess(demo))
.catch(error => this.props.demoFetchError(error));
}
and my return
and my return
and my return
and my return
const { demo } = this.props;
and my render
and my render
and my render
and my render
<p>
Categories :
{
Object.values(`${demo.categories}`).map((category) => {
return (
<ul>
<li>
{category.toString()}
</li>
</ul>
);
})}
</p>
How to solve this issue?
EDIT:
Thanks for your help. I want to read 'categories' and map it to show value of 'de', 'fr','us, 'uk' ... but I'm completely lost !
{
Object.keys(demo).filter((x) => { return x === 'categories'; }).map((category) => {
return (
<ul>
<li>
{category.de}
</li>
</ul>
);
})}
something like that :
{category.de > 0 ? `de : ${category.de}` : ''}
{category.us > 0 ? `us : ${category.us}` : '' }
Your category is object and you are trying to convert it to string. Try below code.
If you want key then
<li>
{Object.keys(category)[0]}
</li>
If you want value then
<li>
{Object.values(category)[0]}
</li>

Display array value with multiple objects

I need to display the values in my UsersData array, same as array numbers, but I can not do that in ReactJS.
Here's an example available in CodeSandbox.
https://codesandbox.io/s/n08n2m7mpj
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const usersData = [
{
total: 3,
data: [
{ id: 1, name: "Tania", username: "floppydiskette" },
{ id: 2, name: "Craig", username: "siliconeidolon" },
{ id: 3, name: "Ben", username: "benisphere" }
]
}
];
const numbers = [1, 2, 3, 4, 5];
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{numbers.map((number, index) => (
<li key={index}>{number}</li>
))}
{usersData.length > 0 ? (
usersData.map((data, index) => <div key={index}>Nome: {data.name}</div>)
) : (
<div>No users </div>
)}
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
1) usersData is an array containing one element (an object)
2) You need to iterate over the data array of that object and display the value of name property for each its objects.
{usersData[0].data.length > 0 ? (
usersData[0].data.map((obj, index) => <div key={index}>Nome: {obj.name}</div>)
) : (
<div>No users </div>
)}
Forked update
Your usersData is an array usersData=[] which contains an object usersData=[{}] which itself contains the array of data usersData=[{data: []}] so you need to change your variable to an object and use the map function on the array of data inside it like so
const usersData = {
total: 3,
data: [
{ id: 1, name: "Tania", username: "floppydiskette" },
{ id: 2, name: "Craig", username: "siliconeidolon" },
{ id: 3, name: "Ben", username: "benisphere" }
]
};
and your loop would become
{usersData.data.length > 0 ? (
usersData.data.map((user, index) => <div key={index}>Nome: {user.name}</div>)
) : (
<div>No users </div>
)}
You need to do
usersData[0].data.map(({name}, index) => <div key={index}>Nome: {name}</div>)
Becaise you are not accessing the data array in your code above
usersData.map((userData, index) => {
return userData.data.map(item => {
return <div key={index + item.id}>Nome: {item.name}</div>;
});
});

React/React-Router - TypeError: Cannot read property of undefined

I'm a React novice, trying my hand at creating my first application. I've been trying to keep it super simple so far whilst following some tutorials and documentation.
The below code is causing a TypeError as shown in the image here
error screenshot
Here is my code:
import React from 'react';
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
const App = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/hospitals">Find a Patient</Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/hospitals" component={Hospitals}/>
</div>
</Router>
)
const Home = () => (
<div>
<h2>Home</h2>
</div>
)
const HOSPITALS = [
{ id: 0, name: 'St James', patients: [
{ id: 1, location: 'Maple ward' },
{ id: 2, location: 'Birch ward' },
{ id: 3, location: 'Pine ward' }
]},
{ id: 1, name: 'Harrogate Hospital', patients: [
{ id: 4, location: 'Sycamore ward' },
{ id: 5, location: 'Fern ward' },
{ id: 6, location: 'Oak ward' }
]},
{ id: 2, name: 'Leeds General Infirmary', patients: [
{ id: 7, location: 'Trout ward' },
{ id: 8, location: 'Eel ward' },
{ id: 9, location: 'Salmon ward' }
]}
]
const find = (id) => HOSPITALS.find(p => p.id === id)
const Hospitals = ( {match} ) => {
let hospitals = HOSPITALS.map((hospital) => {
return (
<li key={hospital.id}>
<Link to={`${match.url}/${hospital.id}/patients`} >
{hospital.name}
</Link>
</li>
)
});
return (
<div>
<h2>Hospitals</h2>
<ul>
{hospitals}
</ul>
<hr/>
<Route path={`${match.url}/:hospitalID/patients`} component={Patients}/>
</div>
)
}
const Patients = ( {match} ) => {
const hospitalArray = find(match.params.hospitalID)
let patients = hospitalArray.patients.map((patient) => {
return (
<li key={patient.id}>
<Link to={`${match.url}/${patient.id}`} >
{patient.location}
</Link>
</li>
)
});
return (
<div>
<h2>Patient for {match.params.hospitalID}</h2>
<ul>
{patients}
</ul>
<hr/>
<Route path={`${match.url}/:patientID`} component={PatientDetail}/>
</div>
)
}
const PatientDetail = ({match}) => (
<div>
<h2>Patient details for {match.params.patientID}</h2>
</div>
)
export default App;
Any help or insights would be much appreciated.
Thanks!

Categories

Resources