Chartjs populate data with Axios response - reactjs

I am attempting to have the data on the chart populate based on the set of data the user selects i.e past 24-hours, past week, etc. I am saving the data and the labels in state. The labels update according to the selected time frame, but none of the data populates. I have console logged the data (this.state.data.datasets[0].data[0]) and it is the correct data.
Here is my code:
class ChartDemo extends Component {
state = {
target: 20,
timeFrame: "past-hours",
totalSales: [],
data: {
labels: [],
datasets: [
{
label: "",
backgroundColor: "",
// data results
data: []
}
]
},
chartIsLoaded: false,
}
getData = (start, end) => {
API.getData(start, end)
.then(res =>
this.setState(state => {
// if any sales have occured in selected time period
if (res.data[0] !== undefined) {
let total = res.data[0].profit.toFixed(2);
let totalString = total.toString();
const totalSales = state.totalSales.concat(totalString);
return {
totalSales
};
} else {
// set to zero if no sales
const noSale = "0.00";
const totalSales = state.totalSales.concat(noSale);
return {
totalSales
};
}
})
)
.catch(error => console.log( error));
}
UNSAFE_componentWillMount() {
this.setTimeFrame();
}
setTimeFrame() {
const day-one = 2019-08-01;
const day-two = 2019-08-02;
const timeFrame = this.state.timeFrame;
this.setState({ target: 20 });
if (timeFrame === "past-hours") {
this.getData(day-one, day-two);
if (this.state.totalSales.length < 8) {
this.setState({ target: 7, chartIsLoaded: true });
setTimeout(
function () {
this.setState(prevState => ({
data: {
...prevState.data,
labels: [
timeset-one,
timeset-two,
timeset-three,
timeset-four,
timeset-five,
timeset-six,
timeset-seven,
timeset-eight,
],
datasets: [{
...prevState.data.datasets,
label: "24-hour Profit in $",
backgroundColor: "rgb(1,41,95)",
data: [this.state.totalSales]
}]
}
}))
}.bind(this), 1000
)
}
}
}

I solved this by removed the [] around this.state.totalSales. I was essentially putting an array into another array.

Related

How to I pass a filters variable to useInfiniteQuery with pageParam?

I'm trying to pass the queryKey variable alongside the pageParam in useInfiniteQuery? I've tried for a while but:
Cannot get the page data
In some cases, the data is rendered repeatedly.
How should I pass the variables?
export const fetchInfiniteVariants = async (
filters = {},
{ pageParam = 0 }
) => {
const records = await axios.get(baseURL, {
headers: authHeader,
params: {
pageSize: 24,
offset: pageParam,
fields: [
"name",
"packshot",
"packshot_size",
"brand_logo",
"price",
"slug",
],
// filterByFormula: `({validated} = 1)`,
filterByFormula: `(${filterByFields(filters)})`,
"sort[0][field]": "priority",
"sort[0][direction]": "asc",
},
})
return records
}
export const useInfiniteVariantsQuery = (
initialRecords,
offset,
filters = { brand: "HAY" }
) => {
const infiniteVariantsQuery = useInfiniteQuery(
["infiniteVariants", filters],
() => fetchInfiniteVariants(filters),
{
initialStale: true,
staleTime: 6000,
getNextPageParam: (lastPage, pages) => lastPage.data.offset,
}
)
return {
...infiniteVariantsQuery,
}
}
The queryFn you're passing to useInfiniteQuery has request context as a parameter to that callback, as documented on the useInfiniteQuery page:
Receives a QueryFunctionContext object with the following variables:
queryKey: EnsuredQueryKey: the queryKey, guaranteed to be an Array
pageParam: unknown | undefined
You can destructure and retrieve your queryKey from that, as below:
export const useInfiniteVariantsQuery = (
initialRecords,
offset,
filters = { brand: "HAY" }
) => {
const infiniteVariantsQuery = useInfiniteQuery(
["infiniteVariants", filters],
({ queryKey, pageParam }) => fetchInfiniteVariants(queryKey[1], pageParam),
{
initialStale: true,
staleTime: 6000,
getNextPageParam: (lastPage, pages) => lastPage.data.offset,
}
)
return {
...infiniteVariantsQuery,
}
}

map over multiple arrays and only return specific ones

I currently have an axios get request that fetches data from a nasa API and returns it into a list of arrays.
getDataHandler= () => {
axios.get('https://api.nasa.gov/neo/rest/v1/neo/browse?api_key=DEMO_KEY',)
.then((response) => {
const restructuredData = response.data.near_earth_objects.map(
({ name, estimated_diameter, close_approach_data }) => {
const close_approaches = close_approach_data && close_approach_data.length
? close_approach_data.map(({ orbiting_body }) => orbiting_body)
: ["no orbited planet"] // If the array doesn't exist, just use an empty array.
return [
name,
estimated_diameter.kilometers.estimated_diameter_min,
estimated_diameter.kilometers.estimated_diameter_max,
close_approaches[0]
]
})
})
It returns a list of arrays that look like this:
0: (4) ["21277 (1996 TO5)", 1.6016033798, 3.5812940302, "Mars"]
1: (4) ["162038 (1996 DH)", 1.2721987854, 2.844722965, "no orbited planet"]
2: (4) ["189058 (2000 UT16)", 1.332155667, 2.978790628, "Earth"]
3: (4) ["276274 (2002 SS41)", 0.9650614696, 2.1579430484, "Earth"]
4: (4) ["322913 (2002 CM1)", 1.214940408, 2.7166893409, "Jupiter"]
5: (4) ["435730 (2008 UK90)", 0.4411182, 0.9863702813, "no orbited planet"]
Then it gets the list and setState it.
Problem is I have a dropDown menu to only show data from specific planets. So I was wondering if it's possible to map of it again and only keep the ones that are equal to the current selected planet.
And if no planets are selected return all of them.
code i have so far
class MainPage extends Component {
state = {
data: [['name', 'min estimated diameter', 'max estimated diameter', { role: "planet" }]],
dropDownOptions: [
{ value: 'all', label: 'All' },
{ value: 'earth', label: 'Earth' },
{ value: 'mars', label: 'Mars' },
{ value: 'mercury', label: 'Mercury' },
{ value: 'venus', label: 'Venus' },
{ value: 'saturn', label: 'Saturn' },
{ value: 'jupiter', label: 'Jupiter' },
{ value: 'no orbited planet', label: 'No orbited planet'}
],
SelectedDropDownOption: { value: 'all', label: 'All' },
}
componentDidMount() {
this.getDataHandler()
}
getDataHandler= () => {
axios.get('https://api.nasa.gov/neo/rest/v1/neo/browse?api_key=DEMO_KEY',)
.then((response) => {
const restructuredData = response.data.near_earth_objects.map(
({ name, estimated_diameter, close_approach_data }) => {
const close_approaches = close_approach_data &&
close_approach_data.length
? close_approach_data.map(({ orbiting_body }) => orbiting_body)
: ["no orbited planet"]
return [
name,
estimated_diameter.kilometers.estimated_diameter_min,
estimated_diameter.kilometers.estimated_diameter_max,
close_approaches[0]
]
}
)
const joined = this.state.data.concat(restructuredData)
this.setState({ data: joined })
})
.catch(function (error) {
console.log(error);
})
}
DropDownChangeHandler= (SelectedDropDownOption) => {
console.log("hello")
this.setState({SelectedDropDownOption});
}
render () {
console.log(this.state.data)
console.log(this.state.SelectedDropDownOption)
console.log(this.state.SelectedDropDownOption.value)
return (
<React.Fragment>
<DropDown options={this.state.dropDownOptions} onChange={this.getPlanetInformation}/>
<Chart chartData={this.state.data} />
</React.Fragment>
);
}
}
export default MainPage;
You can use filter method to achieve your goal. You loop over every sub array and you keep only those which includes the require planet name passed as function parameter.
const arrayList = [["21277 (1996 TO5)", 1.6016033798, 3.5812940302, "Mars"], ["162038 (1996 DH)", 1.2721987854, 2.844722965, "no orbited planet"], ["189058 (2000 UT16)", 1.332155667, 2.978790628, "Earth"],["276274 (2002 SS41)", 0.9650614696, 2.1579430484, "Earth"], ["322913 (2002 CM1)", 1.214940408, 2.7166893409, "Jupiter"]]
const getPlanetInformation = (planet) => {
const information = arrayList.filter(item => item.includes(planet))
console.log(information)
return information.length ? information : arrayList
}
If there is no planet selected from your dropdown value or the selected doesn't exists inside your array, you can just return the initial value.

How can I manipulate a 2D array in React?

i tried to save list of equipments in arrays.
i need to add quantity for each equipemnt so i have to transform the one dimensional to two dimensional
how can i change this todeclare in state arrays as 2D?
this.state = {
equipments: [{
number: ''
},{
number: ''
}]};
and how to setsate ?
handleSubmit(event) {
const orderData = {
equipments: this.state.equipments.map(equipment => {
return {equipemnt: equipment.number}
})
};
createOrder(orderData);
}
validateEquipment = (equipmentNumber) => {
if(equipmentNumber.length === 0) {
return {
validateStatus: 'error',
errorMsg: 'Please enter a choice!'
}
} else if (equipmentNumber.length > 50) {
return {
validateStatus: 'error',
errorMsg: `Choice is too long (Maximum 50 characters allowed)`
}
} else {
return {
validateStatus: 'success',
errorMsg: null
}
}
}
handleEquipmentChange(event, index) {
const equipments = this.state.equipments.slice();
const value = event.target.value;
equipments[index] = {
number: value,
...this.validateEquipment(value)
}
this.setState({
equipments: equipments
});
}
it would be easier if you use object instead of array
this.state = {
equipments: {
eq1: { qty: 0 },
eq2: { qty: 0 }
}
}
adding / updating new equipment would be as simple as:
addOrUpdateQty(id, qty) {
this.setState({ equipments: {...this.state.equipments, [id]: { qty }} })
}

Multiple fetch requests with setState in React and pie chart

My query was taking more than 2 mins to execute, henceforth it was getting timeout in browser. So now I have break the query and now running as a separate APIs which is helpful, but now I don't know how to handle these three requests so that it can render the data.
Note: The API's data are getting stored in the State component of react, here it is "Data".
Now I have a logic but can anyone give me a direction how to implement it.
Logic: Before storing the result of API's directly into state component, we can store it into different array, then we can iterate through this array for the use of pie chart then this data can be stored into the state component which can be used to render the pie chart in "Render" function.
Here the I am making three different API calls at the same time and storing it, here the result of the API's are directly been stored in the state component:
componentDidMount() {
Promise.all([
fetch("http://localhost:4000/api/EMEA/E_claimQuarter"),
fetch("http://localhost:4000/api/EMEA/E_claimQuarter1"),
fetch("http://localhost:4000/api/EMEA/E_claimQuarter2")
])
.then(([res1, res2, res3]) =>
Promise.all([res1.json(), res2.json(), res3.json()]))
.then(([data1, data2, data3]) =>
this.setState({
// Data: data1, data2, data3,
Data: {
labels: [
"FY19 Q1[NOV-JAN]",
"FY19 Q2[FEB-APR]",
"FY18 Q3[SEP-NOV]"
],
datasets: [
{
label: "",
data: data1,
backgroundColor: [
"rgba(255,105,145,0.6)",
"rgba(155,100,210,0.6)",
"rgb(63, 191, 191)"
]
}
]
}
})
);
}
This is how you handle the data form API and loop through it then render this data for the various charts which is in my case is Pie Chart:
ComponentDidMount() {
axios.get(`http://localhost:4000/api/APJ/A_claimQuarter`)
***************************************************************
.then(res => {
const claims = res.data;
let claim = [];
claims.forEach(element => {
claim.push(element.CNT1);
});
********************************************************************
this.setState({
Data: {
labels: ['FY19 Q1[NOV-JAN]','FY19 Q2[FEB-APR]','FY18[SEP-NOV]'],
datasets:[
{
label:'',
data: claim ,
backgroundColor:[
'rgba(255,105,145,0.6)',
'rgba(155,100,210,0.6)',
'rgb(63, 191, 191)'
]
}
]
}
});
})
}
I have made some modifications and now it is working fine for me, if anyone want the answer you can look at mine, it is 100% working:
constructor(props) {
super(props);
this.state = {
Data: []
};
}
componentDidMount() {
Promise.all([
fetch("http://localhost:4000/api/EMEA/E_claimQuarter"),
fetch("http://localhost:4000/api/EMEA/E_claimQuarter1"),
fetch("http://localhost:4000/api/EMEA/E_claimQuarter2")
])
.then(([res1, res2, res3]) => Promise.all([res1.json(), res2.json(), res3.json()]))
.then(([data1, data2, data3]) =>
{
console.log(typeof(data1));
const array = [...data1, ...data2, ...data3];
// const A = JSON.strigify(array);
console.log('hi');
console.log(array);
console.log(data1);
// console.log(A);
let claim = [];
array.forEach(element => {
claim.push(element.COUNT);
});
console.log(claim);
this.setState({
// Data: data1, data2, data3,
Data: {
labels: [
"FY19 Q1[NOV-JAN]",
"FY19 Q2[FEB-APR]",
"FY18 Q3[SEP-NOV]"
],
datasets: [
{
label: "",
data: claim,
backgroundColor: [
"rgba(255,105,145,0.6)",
"rgba(155,100,210,0.6)",
"rgb(63, 191, 191)"
]
}
]
}
})
});
}
Based on OP's own answer, here's a more generalised solution :
componentDidMount(graphData) {
return Promise.all(graphData.map(dataObj => dataObj.url))
.then(results => Promise.all(results.map(res => res.json())))
.then(results => this.setState({
'Data': {
'labels': graphData.map(dataObj => dataObj.label),
'datasets': [
{
'label': '',
'data': results.reduce((prev, next) => prev.concat(next), []),
'backgroundColor': graphData.map(dataObj => dataObj.bgColor)
}
]
}
}));
}
As you see, Array methods .map() and .reduce() make for some nice compact code.
Call as follows:
var quartersData = [
{ 'url':'http://localhost:4000/api/EMEA/E_claimQuarter', 'label':'FY19 Q1[NOV-JAN]', 'bgColor':'rgba(255,105,145,0.6)' },
{ 'url':'http://localhost:4000/api/EMEA/E_claimQuarter1', 'label':'FY19 Q2[FEB-APR]', 'bgColor':'rgba(155,100,210,0.6)' },
{ 'url':'http://localhost:4000/api/EMEA/E_claimQuarter2', 'label':'FY18 Q3[SEP-NOV]', 'bgColor':'rgb(63, 191, 191)' }
];
componentDidMount(quartersData)
.then(() => {
console.log('complete');
});

Mongoose/Mongo: Update Not Saving

I'm extremely perplexed by this issue that I'm having with mongo/mongoose. I'm essentially trying to get an array of products, delete a certain product from the array, and then update the shopping chart with the new array that omits the selected product. Here's the snippet of code I'm dealing with:
const remove = (req, res, next) => {
console.log('here is the product id ' + req.body.cart.product)
delete req.body._owner // disallow owner reassignment.
Cart.find({_id: req.user.cartId})
.then((products1) => {
console.log("array of products: " + products1[0].product)
const index = products1[0].product.indexOf(req.body.cart.product)
console.log("index valeu: " + index)
if (index > -1) {
products1[0].product.splice(index, 1)
return products1[0].product
}
return products1[0].product
})
.then((products2) => {
console.log('Second Promise Input: ' + products2)
Cart.update({_id: req.user.cartId}, {$set: {product: products2}})
})
.then(() => res.sendStatus(204))
.catch(next)
}
And here's the output from my server:
Server listening on port 4741
here is the product id 5952b57ea52d092b8d34c6b0
array of products: 5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0
index valeu: 0
Second Promise Input: 5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0,5952b57ea52d092b8d34c6b0
PATCH /carts-decrease/595b037e128cfd37e0c864d7 204 38.773 ms
According to my console.logs, I'm getting the array just the way I want it but it simply does not update the shopping cart with the new array. I've been staring at this code for far too long and I'd appreciate a second set of eyes on this. Thanks.
P.S. Ignore the fact that the product ids are all the same, its just a testing variable
Cart Schema:
'use strict'
const mongoose = require('mongoose')
const cartSchema = new mongoose.Schema({
product: {
type: Array,
required: false
},
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: false
}
}, {
timestamps: true,
toJSON: {
virtuals: true,
transform: function (doc, ret, options) {
const userId = (options.user && options.user._id) || false
ret.editable = userId && userId.equals(doc._owner)
return ret
}
}
})
const Cart = mongoose.model('Cart', cartSchema)
module.exports = Cart
Product Schema:
'use strict'
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
description: {
type: String,
required: true
}
}, {
toJSON: {
virtuals: true
}
})
const Product = mongoose.model('Product', productSchema)
module.exports = Product
Show request:
const show = (req, res) => {
const product = {}
product.array = []
// console.log(req.cart.product)
const promises = []
Promise.all(req.cart.product.map(function (id) {
return Product.find({_id: ObjectId(id)})
})).then(function (products) {
console.log(products)
req.cart.product = products
return res.json({
cart: req.cart.toJSON({virtuals: true, user: req.user})
})
}).catch(function (err) {
console.log(err)
return res.sendStatus(500)
})
}
I would recommend you to slightly modify your cartSchema and store products in the form of an array of embedded documents:
const cartSchema = new mongoose.Schema({
products: [{
name: { type: String },
price: { type: Number }
...
}]
...
});
If you do this you can simply use the $pull update operator to remove products from your cart:
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
In your case the query should then look like this:
Cart.update(
{ _id: req.user.cartId },
{ $pull: { products: { '_id': req.body.cart.product } }}
);
As the embedded documents will have their own ObjectId there will only be one document matching the query.

Resources