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
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 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
Expected effect:
Render 4 checkbox (from this.state.people):
Paul
Martin
Joseph
Gregor
Based on this.state.peopleChecked checked
Martin
Gregor
Code here: https://stackblitz.com/edit/react-bootstrap-examples
At stackblitz, I have a problem installing react-bootstrap
I have rendered people - 4 checkboxes. How to mark Martin, Gregor among these 4 people based on the 'peopleChecked' array?
class App extends Component {
constructor() {
super();
this.state = {
people: [
{
'firstname': "Paul",
'id': "1"
},
{
'firstname': "Martin",
'id': "2"
},
{
'firstname': "Joseph",
'id': "3"
},
{
'firstname': "Gregor",
'id': "4"
}
],
peopleChecked: [
{
'firstname': "Martin",
'id': "2"
},
{
'firstname': "Gregor",
'id': "4"
}
]
}
}
render() {
return (
<div>
{this.state.people.map(person => (
<div key={person.id} className="mb-1">
<Form.Check
type={'checkbox'}
id={person.id}
label={person.firstname}
/>
</div>
))}
</div>
);
}
}
You can do something like this:
<Form.Check
type={'checkbox'}
id={person.id}
label={person.firstname}
checked={this.state.peopleChecked.some(({ id, firstname }) => (id === person.id && firstname === person.firstname))}
/>
I have a scrolling menu items, and the titles of each item is hardcoded into a const, along side with the id
const list = [
{ name: "category1", id: 0 },
{ name: "category2", id: 1 },
{ name: "category3", id: 2 },
{ name: "category4", id: 3 },
{ name: "category5", id: 4 },
{ name: "category6", id: 5 },
{ name: "category7", id: 6 },
{ name: "category8", id: 7 }
];
I have a json file that contains the category name for each child:
{
"results": [
{
"category": "category1",
"name": {
"title": "mr",
"first": "ernesto",
"last": "roman"
},
"email": "ernesto.roman#example.com",
"id": {
"name": "DNI",
"value": "73164596-W"
},
"picture": {
"large": "https://randomuser.me/api/portraits/men/73.jpg",
"medium": "https://randomuser.me/api/portraits/med/men/73.jpg",
"thumbnail": "https://randomuser.me/api/portraits/thumb/men/73.jpg"
}
},
{
"category": "category2",
"name": {
"title": "mr",
"first": "adalbert",
"last": "bausch"
},
"email": "adalbert.bausch#example.com",
"id": {
"name": "",
"value": null
} etc....
I want to show these categories "category": "category1", as the titles of my menu, I now that I need to start stateless and add them from the JSON, the fetching part from the JSON is done locally in componentDidMount, but I am not sure how can I map them into appearing as menu names to make the menu dynamic, I basically want the same output but from the json not hardcoded. here is a sandbox snippet, would appreciate the help.
https://codesandbox.io/s/2prw4j729p?fontsize=14&moduleview=1
Just convert the JSON output to an object like list with a map function from the results and then set is as MenuItems on the state, which is what you pass to the function on render(). Like that.
import React, { Component } from "react";
import ScrollMenu from "react-horizontal-scrolling-menu";
import "./menu.css";
// One item component
// selected prop will be passed
const MenuItem = ({ text, selected }) => {
return (
<div>
<div className="menu-item">{text}</div>
</div>
);
};
// All items component
// Important! add unique key
export const Menu = list =>
list.map(el => {
const { name, id } = el;
return <MenuItem text={name} key={id} />;
});
const Arrow = ({ text, className }) => {
return <div className={className}>{text}</div>;
};
export class Menucat extends Component {
state = {
selected: "0",
MenuItems: []
};
componentDidMount() {
fetch("menu.json")
.then(res => res.json())
.then(result => {
const items = result.results.map((el, idx) => {
return { name: el.category, id: idx };
});
this.setState({
isLoaded: true,
MenuItems: items
});
});
}
render() {
const { selected, MenuItems } = this.state;
// Create menu from items
const menu = Menu(MenuItems, selected);
return (
<div className="App">
<ScrollMenu
data={menu}
selected={selected}
onSelect={this.onSelect}
alignCenter={true}
tabindex="0"
/>
</div>
);
}
}
export default Menucat;
Cheers!
Looks like you don't have to hard code your category list at all. In your componentDidMount() fetch the json and group the results into separate categories like this:
const json = {
"results": [
{
category: "category1",
name: "Fred"
},
{
category: "category1",
name: "Teddy"
},
{
category: "category2",
name: "Gilbert"
},
{
category: "category3",
name: "Foxy"
},
]
}
const grouped = json.results.reduce((acc, cur) => {
if (!acc.hasOwnProperty(cur.category)) {
acc[cur.category] = []
}
acc[cur.category].push(cur)
return acc;
}, { })
// parent object now has 3 properties, namely category1, category2 and category3
console.log(JSON.stringify(grouped, null, 4))
// each of these properties is an array of bjects of same category
console.log(JSON.stringify(grouped.category1, null, 4))
console.log(JSON.stringify(grouped.category2, null, 4))
console.log(JSON.stringify(grouped.category3, null, 4))
Note that this json has 4 objects in result array, 2 of cat1, and 1 of cat 2 and cat3. You can run this code in a separate file to see how it works. Ofcourse you will be fetching the json object from server. I just set it for demonstration.
Then set teh state:
this.setState({ grouped })
Then in render() you only show the categories that have items like:
const menuBarButtons = Object.keys(this.state.grouped).map((category) => {
/* your jsx here */
return <MenuItem text={category} key={category} onClick={this.onClick} blah={blah}/>
/* or something , it's up to you */
})
I'm assuming you're showing the items based on the currently selected category this.state.selected. So after you have rendered your menu, you would do something like:
const selectedCatItems = this.state.grouped[this.state.selected].map((item) => {
return <YourItem name={item.name} key={item.id} blah={blah} />
})
Then render it:
return (
<div className="app">
<MenuBar blah={blah}>
{menuBarButtons}
</Menubar>
<div for your item showing area>
{selectedCatItems}
</div>
</div>
)
Also, don't forget to change your onClick() so that it sets this.state.selected state properly. I believe you can figure that out yourself.
Hope it helps.
PS: I didn't write a whole copy/paste solution to your problem simply because I'm reluctant to read and understand your UI details and the whole component to component data passing details..
I am making an AJAX request inside my export default class List extends React Component. It works fine and I see the requested array being returned in the form of:
[{...}, {...}, ...]
where each object inside the return is structured like this:
{
description: "bla",
id: "5b4915c37ae56418fcddb88f",
link: "www.website.com",
name: "bla",
position: "bla",
requirements: {
age: 99,
citizenship: "bla",
degree: "bla"
},
salary: "1",
state: "bla"
}
The return is set in the component's state. My render function looks like this:
render() {
let entries = this.state.listEntries
let mapper = entries.forEach((item,index) => {
console.log(entries)
return (
<li key={index}>
{item.name}
{item.position}
</li>
)
})
return (
<div className="listWrapper">
<HeaderBar props={this.state.props}/>
<ul className="list">
{mapper}
</ul>
</div>
)
}
React doesn't show the item.name or item.position, or any other item entry in the DOM. It seems like such a simple problem, but I just can't figure out what the issue is. There is no error in the console, it just doesn't display.
As forEach does not return anything you should use map for this kind of situations. Also, using index as a key can cause some problems, so you can use item.id instead of index.
class App extends React.Component {
state = {
listEntries: [
{
description: "bla",
id: "5b4915c37ae56418fcddb88f",
link: "www.website.com",
name: "bla1",
position: "bla1",
requirements: {
age: 99,
citizenship: "bla",
degree: "bla"
},
salary: "1",
state: "bla"
},
{
description: "bla",
id: "5b4915c37ae56468fcddb88f",
link: "www.website.com",
name: "bla2",
position: "bla2",
requirements: {
age: 99,
citizenship: "bla",
degree: "bla"
},
salary: "1",
state: "bla"
}
]
}
render() {
let entries = this.state.listEntries
let mapper = entries.map((item) => {
console.log(entries)
return (
<li key={item.id}>
{item.name}
{item.position}
</li>
)
})
return (
<div className="listWrapper">
<ul className="list">
{mapper}
</ul>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>