I am trying to map parent comments and then within the map function I want to map the corresponding nested child comments that are only one level deep.
For some reason when I try to do this all the nested child comments display below the first parent comment.
I have two arrays:
parentComments: [
{
id: "1",
comment: "First parent comment"
},
{
id: "2",
comment: "Second parent comment"
},
]
childComments: [
{
id: "3",
comment: "First child comment",
parentCommentId: "1"
},
{
id: "4",
comment: "Second child comment",
parentCommentId: "2"
},
]
Here is the code I am trying:
{parentComments.map((parentComment) => (
<ul>
{parentComment.comment}
<li>
{" "}
{childComments.map((childComment) => (
<>
{childComments.find(
(e) => e.parent_comment_id === comment.id
)
? childComment.comment
: ""}
</>
))}
</li>
</ul>
))}
What I would expect to happen is each parent comment is mapped through, if a child comments parentCommentId equals the id of the parent comment being mapped, it would display the child comment below it.
At first make new array like this then
let parentComments =[
{
id: "1",
comment: "First parent comment"
},
{
id: "2",
comment: "Second parent comment"
},
]
let childComments= [
{
id: "3",
comment: "First child comment",
parentCommentId: "1"
},
{
id: "4",
comment: "Second child comment",
parentCommentId: "2"
},
];
let mapArray =parentComments.map(p => ({
...p,
childComments : childComments.filter(c => c.parentCommentId ==p.id)
}));
console.log(mapArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
then you can try
{parentComments.map((parentComment) => (
<ul>
{parentComment.comment}
<li>
{" "}
{childComments.map((childComment) => (
<>
childComment.comment
}
</>
))}
</li>
</ul>
))}
Related
There is a JSON for categories with the following structure
[
{
"category": "Mobiles",
"sub": [
{
"name": "Apple"
},
{
"name": "Samsung"
}
]
},
{
"category": "Televisions",
"sub": [
{
"name": "Lg"
},
{
"name": "Sony"
}
]
}
]
First i load data from backend to a variable called categories (On the backend side im using expressjs and pass data with res.json(JSON.parse(fs.readFileSync('categories.json')))
I want to iterate through categories sub category with
{categories.map(function (category, i) {
return (
<>
<h6 Key={i}>{category.category}</h6> //For example: <h6>Mobiles</h6>
<>... [logic to iterate the current category's sub categories] ...</> //For example: <p>Apple</p> <p>Samsung</p>
</>
);
})}
I tried to use a second map on category.sub like category.sub.map((s,j)=><p Key={j}>{s.name}</p>) but unfortunely i can't get it work, and I can't describe my problem to Google in English so it can be an easy answer and i am the big L
Any help?
Thanks
Try this, uncomment out the console.log to verify data if screen is white.
return (
<>
{categories.map(function (category, i) {
// console.log(category.category );
// console.log(category.sub );
return (
<>
<h6 key={i}>{category.category}</h6>
<>
{category.sub.map(function (sub, j) {
// console.log(category.category + '' + sub.name);
return <p key={j}> {sub.name}</p>;
})}
</>
</>
);
})}
</>
);
Data:
let categories = [
{
category: 'Mobiles',
sub: [
{
name: 'Apple',
},
{
name: 'Samsung',
},
],
},
{
category: 'Televisions',
sub: [
{
name: 'Lg',
},
{
name: 'Sony',
},
],
},
];
I have a map in following structure.
const myMap = {
"title1" : [
{
"id" : "1",
"name" : "n1"
},
{
"id" : "2",
"name" : "n2"
}
],
"title2" : [
{
"id" : "3",
"name" : "n3"
},
{
"id" : "4",
"name" : "n4"
}
]
}
I am trying to run over above map and achieve a list of list of components as follows.
[
[
<MyComponent props={props}/>,
<MyComponent props={props}/>
],
[
<MyComponent props={props}/>,
<MyComponent props={props}/>
]
]
How can I achieve this? Please refer to the code below on my attempt.
Keep getting following error.
Error!Cannot read property 'map' of undefined
My attempt to map and create a list of list of components.
Just for reference, MainComponent accepts a list of list under body key as follows:
<div>
{myMap && <MainComponent
data={{
body: Object.keys(myMap).map((key) => {
const categoryArray = myMap[key];
categoryArray.forEach(category => {
return {
content: <div>
<MyComponent
data={{
id: category.id,
title: category.name,
image: {
href:`https://domain${category.img}`,
alt: category.name,
},
}}
/>,
</div>,
}
})
})
}}
/>}
</div>
I need to render data using React vertical tabs, I have given code which I have tried and also the data coming from API. I am not getting how to loop inside <TabPanel>.
link for codesandbox https://codesandbox.io/s/jovial-darkness-qob1n?file=/src/tab.js
<Tabs
defaultTab="vertical-tab-one"
vertical
className="vertical-tabs"
>
<TabList>
{subProducts.map((subProduct, index) => (
<Tab>{subProduct.subProductName}</Tab>
))}
</TabList>
{subProducts.map((subProduct, index) => (
<TabPanel className="tab-pane fade mt-4 show ">
{subProduct.bookingDetails.map((attr, i) => (
<>
<table id="customers">
<tbody>
<tr>
<td>{attr.name}</td>
<td>{attr.value}</td>
</tr>
</tbody>
</table>
</>
))}
</TabPanel>
))}
</Tabs>
API output:
subProducts: [
{
bookingDetails: [
{
name: "Birthday Decoration",
value: "YES"
},
{
name: "Photographer",
value: "NO"
}
],
subProductName: "Celebration"
},
{
bookingDetails: [
{
name: "Decoration",
value: "YES"
},
{
name: "Video",
value: "NO"
}
],
subProductName: "FamilY"
}
]
In the sandbox you try to map over bookingDetails for each object in the subProducts array, but in the second object of subProducts you have a Details property, but not a bookingDetails property so bookingDetails will be undefined.
So you probably want to change Details to bookingDetails:
subProducts: [
{
bookingDetails: [
{
name: "Birthday Decoration",
value: "YES",
},
{
name: "Photographer",
value: "NO",
},
],
subProductName: "Celebration",
},
{
bookingDetails: [
{
name: "Decoration",
value: "YES",
},
{
name: "Video",
value: "NO",
},
],
subProductName: "FamilY",
},
];
If the API returns Details instead of bookingDetails as in your original question do it the other way around. Change it so it maps over Details instead:
So subProduct.Details.map instead of subProduct.bookingDetails.map.
The data not being displayed correctly on click is because each Tab component need to have a tabFor prop value that corresponds with a TabPanel's tabId prop value. Otherwise react-web-tabs doesn't know what content to show when.
For this example I've used the map's index and called toString on it before passing it to the props as the id needs to be a string. But a more natural id would be to have id fields in your data and use those.
Example Sandbox
I have this JSON data in another file:
{
"feed": [
{
"id": 1,
"text": "Hey everyone I'm looking for help with my meditation, when does everyone do it?",
"messages": [
{
"id": 1,
"text": "I like to do it first thing in the morning and sometimes at night!",
},
{
"id": 2,
"text": "Thanks I'll try that!",
}
]
},
{
"id": 2,
"text": "Have you tried a weighted blanket?",
"messages": [
{
"id": 3,
"text": "Yeah, they're great, I have the 10lb one!",
},
{
"id": 4,
"text": "Thank you!",
}
]
}
]
}
I successfully rendered the two sets of data under "feed" using the map function by doing this:
<div>
{Data.feed.map(feed => {
return(
<>
<h4>{ feed.id }</h4>
<p>{ feed.text }</p>
</>
)})
}
</div>
My question is: how do I also render the inner messages loop? I was told to use a nested .map and here's what I unsuccessfully attempted:
<div>
{Data.feed.map(feed => {
return {feed.messages.map(messages => {
return (
<>
<h4>{ feed.id }</h4>
<p>{ feed.text }</p>
<h5>{ messages.id }</h5>
<p>{ messages.text }</p>
</>
)}
)}
})}
</div>
You were actually close. You currently loop over the feed array only. You need to use a second map() to iterate over the messages too inside every item of the feed.
Check out the snippet below:
function App() {
return (
<div>
{data.feed.map((feed) => (
<React.Fragment key={feed.id}>
<h4>{feed.id}</h4>
<p>{feed.text}</p>
<ul>
{feed.messages.map((message) => (
<li key={message.id}>{message.text}</li>
))}
</ul>
</React.Fragment>
))}
</div>
);
}
const data = {
feed: [
{
id: 1,
text:
"Hey everyone I'm looking for help with my meditation, when does everyone do it?",
messages: [
{
id: 1,
text:
'I like to do it first thing in the morning and sometimes at night!',
},
{
id: 2,
text: "Thanks I'll try that!",
},
],
},
{
id: 2,
text: 'Have you tried a weighted blanket?',
messages: [
{
id: 3,
text: "Yeah, they're great, I have the 10lb one!",
},
{
id: 4,
text: 'Thank you!',
},
],
},
],
};
ReactDOM.render(<App />, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I have a form that displays customer data based on a JSON object received from an initial GET request. I map that information out to display both the customer details and their available offers and I've created an onClick function to highlight their selected offer which maps offerId to an object I've defined in state called cardActive. What I'm trying to do now is create a second onClick function connected to a submit button that fires a POST action returning the following values as the JSON body:
{
"CustomerId" : "1",
"SessionId" : "9636",
"Offer": {
"OfferId" : "1",
"OfferName" : "Business Internet 75"
}
}
I've included my current component below including a dummy JSON object that mimics the response back from that initial GET request
class UsersList extends Component {
constructor() {
super();
this.selectCard = this.selectCard.bind(this);
this.state = {
cardActive: null,
offerName: null,
customerId: null,
customers: [
{
CustomerId: "1",
LastName: "Doe",
FirstName: "Jane",
Address: {
Address1: "1811 Chestnut Street",
Address2: null,
City: "Philadelphia",
State: "Pennsylvania",
Zip: "19103"
},
Offers: [
{
OfferId: "Offer1",
Name: "Offer Number 1",
Products: [
{
ProductId: 1,
ProductName: "Cool stuff"
},
{
ProductId: 2,
ProductName: "Some little stuff"
}
],
Price: "$1"
},
{
OfferId: "Offer2",
Name: "Offer Number 2",
Price: "$2",
Products: [
{
ProductId: 3,
ProductName: "More stuff"
},
{
ProductId: 4,
ProductName: "Hey theres stuff here"
}
]
},
{
OfferId: "Offer3",
Name: "Offer Number 3",
Price: "$3",
Products: [
{
ProductId: 5,
ProductName: "Check out this stuff"
},
{
ProductId: 5,
ProductName: "More stuff"
}
]
}
]
}
]
};
}
selectCard(offerId) {
this.setState({ cardActive: offerId });
}
render() {
return (
<div>
{this.state.customers.map((customer, index) => {
return (
<div key={index + customer.CustomerId}>
<h3>
Name: {customer.LastName}, {customer.FirstName}
</h3>
<h3>Customer ID: {customer.CustomerId}</h3>
<h3>
Address:
<br />
{customer.Address.Address1}
<br />
{customer.Address.City}, {customer.Address.State}{" "}
{customer.Address.Zip}
</h3>
<br />
<h2>Available Offers</h2>
<Grid container spacing={24} justify="center">
{customer.Offers.map((Offer, index) => {
return (
<div
key={index + Offer.OfferId}
onClick={() => this.selectCard(Offer.OfferId)}
>
<Grid item xs={12}>
<div
className={
Offer.OfferId === this.state.cardActive
? "cardActive"
: "card"
}
>
<div className="container">
<h5>
<b>{Offer.OfferId}</b>
</h5>
<h2>{Offer.Name}</h2>
{Offer.Products.map((Product, index) => {
return (
<div key={index + Product.ProductId}>
<p>+ {Product.ProductName}</p>
</div>
);
})}
<h3>{Offer.Price}</h3>
</div>
</div>
</Grid>
</div>
);
})}
</Grid>
</div>
);
})}
<button className="navbuttonSelected">Submit</button>
</div>
);
}
}
export default UsersList;
I added the objects into the state that I'm hoping to populate (offerName, CustomerId and keeping cardActive as the holder for offerId) and now I'm trying to figure out how to write the function to map all of those values to send back via POST. The best I've come up with so far is
submitSelection(offerId, offerName, CustomerId) {
this.setState({
cardActive: offerId,
offerName: offerName,
CustomerId,
SessionId: SessionId
});
}
Any suggestions/examples on how to do this would be a huge help
I think that the best way to handle the data form is by a state property in this case will be something like this :
this.state = {
dataModel:{
cardActive : null,
offerName : null,
customerId : null,
CustomerId : null,
SessionId : null,
},
...
}
]
};
So in your submit function you can just update the data that youve received to the this.state.dataModel.
then you can use axios or somthing to send the dataModel to as the data of the axios method.
Check my sandbox maybe is clearer that way:
https://codesandbox.io/s/8xm00xplm2