Reactjs having problems printing out fetched data - javascript

super noob question. However, I've been stuck with this issue for long enough now. I've been searching and have found the similar issue but have not been able to resolve it. I was hoping someone could point me in the right direction as to what I am doing wrong.
I am fetching data from an API, and I am able to log out the array, however, when I try to print it out I am having no luck. In the beginning, I was passing it through a reducer but then realized that was not ideal. Right now I am trying to get it to work, then I'll refactor the code into a functional component.
fetchOrders = async () => {
await axios.get('http://localhost:4200/ordenes').then( res => {
this.setState({
prescription: res.data
})
})
}
render() {
console.log(this.state.prescription)
return (
<div >
<Paper style={styles.orderCard}id='orderCardContainer' >
<div id="profileCardContainer" style={styles.profileCard}>
<aside className='profileCardContainer'>
<ProfileCard />
</aside>
</div>
{this.renderOrder()}
</Paper>
</div>
)
}
}
The array I receive back from the API looks something like this:
Array(18)
0: {order: Array(3), _id: "5b2af38fb315eb5630a0bc78", physicianName: "Alejandro", patientName: "Alex", createdAt: "2018-06-21T00:38:39.376Z", …}
UPDATE:
class OrderCard extends Component {
constructor(props) {
super(props)
this.state = { prescription: []}
}
fetchOrders = async () => {
const res = await axios.get('http://localhost:4200/ordenes')
this.setState({
prescription: res.data
})
}
componentDidMount() {
this.fetchOrders()
}
renderOrder() {
if (this.state.prescription.length === 0 ) {
return (
<h1>Loading...</h1>
)
} else {
return (
this.state.prescription.map( (x, i) => {
<li>
{console.log(x.patientName)}
<h1>{ x.patientName }</h1>
</li>
})
)}
}
render() {
console.log(this.state.prescription)
return (
<div >
<Paper style={styles.orderCard}id='orderCardContainer' >
<div id="profileCardContainer" style={styles.profileCard}>
<aside className='profileCardContainer'>
<ProfileCard />
</aside>
</div>
<div id='orders' >
{ this.renderOrder() }
</div>
</Paper>
</div>
)
}
}
function mapStateToProps(state) {
return {
auth: state.auth.authenticated,
}
}
export default connect(mapStateToProps, actions)(OrderCard)
BACKEND SCHEMA
const orderObj = new Schema({
name: String,
price: Number,
}, { _id : false })
const orderSchema = new Schema (
{
physicianName: String,
patientName: String,
order: {type: [orderObj]}
},
{
timestamps: true
}
)
POSTMAN API RESULTS
[
{
"order": [
{
"name": "Asteraceae",
"price": 41.24
},
{
"name": "Liliaceae",
"price": 39.24
},
{
"name": "Fabaceae",
"price": 34.91
}
],
"_id": "5b2af38fb315eb5630a0bc78",
"physicianName": "Alejandro",
"patientName": "Alex",
"createdAt": "2018-06-21T00:38:39.376Z",
"updatedAt": "2018-06-21T00:38:39.376Z",
"__v": 0
}
]
Thanks in advance for tips.

Wrong brackets, you're not returning react element, try fixed one.
renderOrder() {
if (this.state.prescription.length === 0 ) {
return (
<h1>Loading...</h1>
)
} else {
return (
this.state.prescription.map((x, i) => (
<li>
{console.log(x.patientName)}
<h1>{ x.patientName }</h1>
</li>
))
)}
}
and fix this
fetchOrders = async () => {
const res = await axios.get('http://localhost:4200/ordenes');
this.setState({
prescription: res.data
});
}

Related

how to setState and update an object within an array

i need your help please :-)
state = {
order: {
createdAt: Date.now(),
products: [
{
leftInStock: "12",
productName: "בלה",
productPrice: "120",
qtyInOrder: 0
}
],
totalPrice: 0,
miniClient: {
id: '',
fullName: ''
}
},
client: null,
isClientSelected: true
}
and this is the function that should preform the update on the object (need to update qtyInOrder).
setQtyForProduct = (product, name) => {
if (name === '+') product.qtyInOrder++
if (name === '-') {
if (product.qtyInOrder === 1) return
else product.qtyInOrder--
}
const { products } = this.state.order
this.setState({ order: { ...this.state.order, products: [...products, product] } }, () => { this.getOrderPrice() })
}
this is how i pass the values
<div className="order-selected-product-list">
{this.state.order.products.map((product, _id) => {
return (
<div key={_id} className="order-product">
<div className="order-selected-product-card">
<div>{product.productName}</div>
<div>{product.qtyInOrder}</div>
</div>
<div className="order-products-qty-btns">
<div onClick={() => this.setQtyForProduct(product, "+")}>+</div>
<div onClick={() => this.removeProductFromOrder(product)}>הסר</div>
<div onClick={() => this.setQtyForProduct(product, "-")}>-</div>
</div>
</div>
)
})}
</div>
i do get the values right , the only thing i caould not manage to do is update the
I know that is something wrong with my setState function cause it adds the products instead of updating the key in it

Implementation problems while using React's Promises

I'm working on an assignment where I need to implement an order management system. The problem is that I need to make a GET call to get all the orders, and for each order I need to make another GET call so I can get the Items of this order.
My question is how can I make those calls and create some data structure of orders and items before rendering everything.
I tried using async/await but I couldn't manage to create this data structure of orders and their related items before everything rendered.
For now I only have the orders GET call handled
async componentDidMount() {
const orders = await api.getOrders()
this.setState({
orders
});
}
I also created a function for the GET calls of the items which returns a Promise<Item[]>
createItemsList = (order: Order) => {
let a = order.items.map((item) => {
return api.getItem(item.id);
});
return Promise.all(a);
};
Any suggestion for a way to combine those two? Thanks in advance!
*** Editing ***
This is the part of the code where I render the orders
{filteredOrders.map((order) => (
<div className={'orderCard'}>
<div className={'generalData'}>
<h6>{order.id}</h6>
<h4>{order.customer.name}</h4>
<h5>Order Placed: {new Date(order.createdDate).toLocaleDateString()},
At: {new Date(order.createdDate).toLocaleTimeString()}</h5>
</div>
<Fulfilment order={order}/>
<div className={'paymentData'}>
<h4>{order.price.formattedTotalPrice}</h4>
<img src={App.getAssetByStatus(order.billingInfo.status)}/>
</div>
<ItemsList subItemsList={order.items} api={api}/>
</div>
))}
The component ItemsList is where I render the Items of a specific order, and order.items is not the items itself but an array of items ID and quantities which I get with each order
I suggest you move the data retrieval into each component.
Check the sandbox here
import React, { PureComponent } from "react";
const fakeOrderItems = {
1: [
{
id: 1,
name: "Ramen",
qty: 1
},
{
id: 1,
name: "Beer",
qty: 1
}
],
2: [
{
id: 1,
name: "Steak",
qty: 1
},
{
id: 2,
name: "Iced Tea",
qty: 1
}
]
};
const fakeOrders = [
{
id: 1,
name: "Table 1",
totalItems: 2
},
{
id: 2,
name: "Table 3",
totalItems: 2
}
];
const fakeApi = {
getOrders() {
return new Promise((resolve) =>
setTimeout(() => resolve(fakeOrders), 3000)
);
},
getOrderItems(id) {
return new Promise((resolve) =>
setTimeout(() => resolve(fakeOrderItems[id]), 3000)
);
}
};
class OrderItem extends PureComponent {
render() {
const { id, name, qty } = this.props;
return (
<div style={{ marginBottom: 10 }}>
<span>
{id}. {name} qty:{qty}
</span>
</div>
);
}
}
class OrderItemList extends PureComponent {
state = {
orderItems: []
};
componentDidMount() {
fakeApi
.getOrderItems(this.props.orderId)
.then((orderItems) => this.setState({ orderItems }));
}
render() {
const { orderItems } = this.state;
if (!orderItems.length) {
return <span>Loading orderItems...</span>;
}
return orderItems.map((item) => (
<OrderItem key={item.id + item.name} {...item} />
));
}
}
class Order extends PureComponent {
render() {
const { id, name } = this.props;
return (
<div style={{ marginBottom: 10 }}>
<div>
<span>Order #{id}</span>
</div>
<div>
<span>For table {name}</span>
</div>
<OrderItemList orderId={id} />
</div>
);
}
}
class OrderList extends PureComponent {
state = {
orders: []
};
componentDidMount() {
fakeApi.getOrders().then((orders) => this.setState({ orders }));
}
render() {
const { orders } = this.state;
if (!orders.length) {
return <div>Loading orders...</div>;
}
return orders.map((order) => <Order key={order.id} {...order} />);
}
}
export default function App() {
return <OrderList />;
}
Create a separate method outside that gets the data you need.
First get the orders from the API. Then loop through each order and call the api again for each item. Await the Promise.all to wait for each item in the order to finish, then concatenate the result to an array where you store all the fetched items. Then after the loop is finished return the results array.
In your componentDidMount call this method and update the state based on the result that the promised returned.
state = {
orders: []
}
async getOrderItems() {
let orderItems = [];
const orders = await api.getOrders()
for (const order of orders) {
const items = await Promise.all(
order.items.map((item) => api.getItem(item.id))
)
orderItems = [...orderItems, ...items]
}
return orderItems
}
componentDidMount() {
this.getOrderItems().then(orders => {
this.setState({
orders
})
})
}
render() {
if (this.state.orders.length === 0) {
return null
}
return (
{this.state.orders.map(order => (
// Render content.
)}
)
}
You can try this solution.I was stuck in the same issue a few days ago.So what it does is that setState renders after createItemsList function is run
async componentDidMount() {
const orders = await api.getOrders()
this.setState({
orders
}),
() => this.createItemsList()
}

How to automatically change an img depending on boolean value in JSON file

I have a JSON file:
[
{
"id": 1,
"availability": false
},
{
"id": 2,
"availability": true
}
]
What I would like to achieve is to automatically display an image of a tick if availability : true and to display an image of a cross if availability : false.
For example these are the names of the two images:
tick.jpg
cross.jpg
This is my code so far:
import React, { Component } from "react";
import "./styles.css";
class GetOnlinePosts extends Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
posts: []
};
}
componentDidMount() {
fetch("https://api.myjson.com")
.then(response => response.json())
.then(
result => {
this.setState({
isLoaded: true,
posts: result
});
},
error => {
this.setState({
isLoaded: true,
error
});
}
);
}
render() {
const { error, isLoaded, posts } = this.state;
const orderedPosts = [
...posts.filter(post => post.availability),
...posts.filter(post => !post.availability)
];
if (error) {
return <div>Error in loading</div>;
} else if (!isLoaded) {
return <div>Loading ...</div>;
} else {
return (
<div>
<div className="tiles">
{orderedPosts.map(post => (
<div key={post.id}>
<div className="tile"></div>
</div>
))}
</div>
</div>
);
}
}
}
export default GetOnlinePosts;
Unfortunately I am unable to have the images included in the with JSON. I would like the images to be within the <div className="tile"> </div> so any help on how to do this would be great. Thanks in advance.
<img src={post.availability ? 'tick.jpg' : 'cross.jpg'} />

I can not show elements of my json - React

I need to retrieve all the information from other fields, not just "Padre" and "Hijo" in the json. I also want to get information from fields like "Id" or "url". I think I can not get them back for the reduced function in componentWillMount, what if I need for "Padre" and "Hijo".
This is an example of my json.
{
"Id": "114",
"Description": "SALUD NORMAL",
"Padre": "CRM",
"Hijo": "Argumentarios",
"URL": "www.test.com",
"Closable": "1",
"Autoload": "0",
"Visible": "1"
}
Nav would be the parent element and content his child, Menu. Menu is the one that creates a button for each of the "Padre" (this.props.menu) and "Hijo" (this.props.submenu) of the json.
This is my code.
class Nav extends Component{
constructor(props){
super(props)
this.state = {
menuSubmenu:[],
abrirSubmenu: false,
}
this.submenuClick = this.submenuClick.bind(this);
}
submenuClick() {
this.setState(state => ({
abrirSubmenu: !state.abrirSubmenu
}));
//alert('Click!')
}
componentWillMount(){
fetch('fake.php')
.then(response => response.json())
.then(menuSubmenu =>{
const PadreMap = menuSubmenu.reduce((acc, obj) => {
if (!acc[obj.Padre]) {
acc[obj.Padre] = {
...obj,
Hijo: [obj.Hijo],
Description: [obj.Description]
};
} else {
!acc[obj.Padre].Hijo.includes(obj.Hijo) && acc[obj.Padre].Hijo.push(obj.Hijo);
//!acc[obj.Padre].Hijo.includes(obj.Hijo) && acc[obj.Padre].Hijo.push(obj.Description)
}
return acc;
}, {});
this.setState({
menuSubmenu: Object.keys(PadreMap).map((padre) => ({
menu: padre,
submenu: PadreMap[padre].Hijo,
id: PadreMap.Id,
descripcion: PadreMap[padre].Description,
url: PadreMap[padre].URL
}))
})
console.log(PadreMap);
})
}
render() {
if (this.state.menuSubmenu.length > 0) {
return(
<nav className="nav">
<div className="menu">
<ul className="list">
{this.state.menuSubmenu.map(datos => <Menu key={datos.id} menu={datos.menu} submenu={datos.submenu} descripcion={datos.descripcion} submenuClick={this.submenuClick} abrirSubmenu={this.state.abrirSubmenu}/>)}
</ul>
<div className="content-bnt">
<button id="desplegar" className='btn btn--rounded'>
<Icon icon="flecha" className='ico-flecha'/>
</button>
</div>
</div>
</nav>
);
}
return (<p>Cargando usuarios...</p>);
}
}
class Menu extends Component{
render(){
return (
<li key={this.props.id} className="list__item">
<button title={this.props.menu} id={"mn-" + this.props.menu} className="desplegable" onClick={this.props.submenuClick}><Icon icon="auriculares" className='ico-auriculares'/>{this.props.menu}</button>
{
this.props.abrirSubmenu
? (
<div id="sb-crm" className="submenu">
{this.props.submenu.map(hijo => <h3 className="nav--title"><Icon icon="descargar" className='ico-descargar'/>{hijo}</h3>)}
<ul className="list">
<li className="list__item">
{this.props.descripcion.map(tercerNivel => <a href={this.props.url} title={this.props.descripcion}>{tercerNivel}</a>)}
</li>
</ul>
</div>
)
: (
null
)
}
</li>
)
}
}
export default Nav;
I need to be able to use all the information of the json, not just "Padre" and "Hijo". I also need the information to be grouped by his "Padre"
This snippet should be suitable:
this.setState(
{
menuSubmenu: Object.keys(PadreMap).map((padre) => {
const {Padre, Hijo, ...rest} = PadreMap[padre];
return {
menu: padre,
submenu: Hijo,
...rest
}
})
}
)

Count occurrences results from API JSON response in React.js

Based on this previous questions I made (Show fetch results in render return() in React.js), from which I received json results, I now need to count the number of sofas that each brand has. For example, Brand X has 2 occurences and Brand Y has 3043.
I get the brand from one sofa by calling myUrlApi + /couch-model on fetch and the json is something like what you can see in the picture below.
Has you can see each sofa has associated to itself a brand. What I want to count is how many sofa each brand has.
I'll put my current code here:
export class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
token: {},
isLoaded: false,
models: []
};
}
componentDidMount() {
/*code to generate token, not needed for the purpose of the question*/
fetch(url + "/couch-model/?limit=9", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: "JWT " + JSON.parse(localStorage.getItem("token")).token
}
})
.then(res => {
if (res.ok) {
return res.json();
} else {
throw Error(res.statusText);
}
})
.then(json => {
this.setState(
{
models: json.results
},
() => {}
);
});
}
render() {
const { isLoaded, models } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div>
{models.map(model => (
<a href="/sofa" key={model.id}>
<div className="Parcelas">
<img src={img_src} className="ParcImage" alt="sofa" />
<h1>Sofá {model.name}</h1>
<h2>
1,200<span>€</span>
</h2>
<p
className="Features"
dangerouslySetInnerHTML={{ __html: model.description }}
/>
<button className="Botao">
<p className="MostraDepois">Ver Detalhes</p>
<span>+</span>
</button>
<img
src="../../img/points.svg"
className="Decoration"
alt="points"
/>
</div>
</a>
))}
</div>
);
}
}
}
Hope I was clear, ask if you have any doubt.
if your results look like this as you said in your post :
{
results: [
{
brand: { name: "Brand-A", image: "", etc: "..." },
category: "A",
code: "AAA",
name: "SofaA",
price: 1200
},
{
brand: { name: "Brand-A", image: "", etc: "..." },
category: "A",
code: "AAA",
name: "SofaB",
price: 1200
},
{
brand: { name: "Brand-B", image: "", etc: "..." },
category: "A",
code: "AAA",
name: "SofaC",
price: 1200
}
]
}
You can add a state property like sofasPerBrand initialized to {}
constructor(props) {
super(props);
this.state = {
token: {},
isLoaded: true,
models: [],
sofasPerBrand: {}
};
}
And add in the setState function in componentDidMount the RIYAJ KHAN reduce function like this :
this.setState(
{
models: json.results,
sofasPerBrand: json.results.reduce((coundData, sofa, index) => {
if (!!coundData[sofa.brand.name]) {
coundData[sofa.brand.name] += 1;
} else {
coundData[sofa.brand.name] = 1;
}
return coundData;
}, {})
},
() => { }
);
then you can declare it in your render function :
const { isLoaded, models, sofasPerBrand } = this.state;
and use it like that any where :
<ul>
{Object.keys(sofasPerBrand).map(brand=>(
<li>{brand} : {sofasPerBrand[brand]}</li>
))}
</ul>
One can use javascript#reducers for it.
models.reduce((coundData,sofa,index)=>{
if(!!coundData[sofa.brand.name]){
coundData[sofa.brand.name] +=1;
}else{
coundData[sofa.brand.name]=1;
}
return coundData;
}, {})

Categories

Resources