Pass second param when map urls with axios.all [duplicate] - javascript

This question already has an answer here:
How to resolve pending promises within map returning an object?
(1 answer)
Closed 10 months ago.
i have a array that contains a object with two values, like this:
[
{
brand: app1,
url: https://myhost.com/api
},
{
brand: app2,
url: https://otherapi.com/api
}
]
I'am using axios.all to made a get request over all urls, and I iterate it with a map, like this:
const getData= axios.all(stuffData.map((item) => axios.get(item.url)))
.then(res => console.log(res.data)
The thing is, how can I pass the second param in the array when i make the map to interate all axios requests? I also need pass the key "brand".
Thanks

Use this:
Promise.all(stuffData.map(async (item) => ({
data: await axios.get(item.url).data,
brand: item.brand
}))).then((data) => {
data.forEach(item=> console.log(item))
})

Related

Getting error of fetched items after refreshing the page

I am fetching my data from external API as usual and this is the typical way I do it:
Fetch API:
const [tshirts, setTshirts] = useState([]);
const fetchData = () => {
fetch('apiEndpoint')
.then((response) => response.json())
.then((data) => {
setTshirts(data[0].clothes.regular.top); // path to my array
})
.catch((error) => {
console.log(error);
});
};
React.useEffect(() => {
fetchData();
}, []);
Map through an array:
const tshirtArray = tshirts.tShirt; // specifying the path
const listItems = tshirtArray.map((item) => <li>{item}</li>);
<ul>{listItems}</ul>
Example of data structure:
[
{
id: 1,
clothes: {
regular: {
top: {
sleeveless: [],
tShirt: [
"image-path-here"
],
.....
.....
.....
When I first time execute the code it works, but after some time or after refreshing the page I get an error of TypeError: Cannot read properties of undefined (reading 'map')
Why is that undefined? The path is correct and fetching the array should be as well. Can not find the reason of it not working.
I don't have reputation to comment, so let me try to clarify it for you through an answer. As #sojin mentioned, you cannot use tshirts.Tshirt since your state is of array type and arrays can't be used like objects, meaning that if there was an object of lets say exampleObject = { type: "shirt", color: "white } you could call it with exampleObject.type. Since you have an array of objects in your state (top that you are saving to state is still object which contains tShirt array), you first have to use index (to tell which object you want to use from the state array) and then you can use it like you wanted. For example, in your example there are 1 objects in state array. Array indexes start at 0. So you could do tshirts[0].tShirt to get the tShirt array from that object.
However, I would edit your code a bit. Instead of using tshirtArray constant, just do listItems from your state:
const listItems = tshirts.map((item) => {item.tShirt[0]});
Note: I've just used index 0 here to demonstrate the finding of the first item in tShirt array. If you want to see all tShirt image paths, then you may need to do nested mapping or other similar solutions.

Why is one API response returning just an object over and array of objects? [duplicate]

This question already has answers here:
Why is "forEach not a function" for this object?
(4 answers)
Closed 1 year ago.
Currently my Api is returning an object instead of an object within an array, however I can't seem to tell the difference between these two routes and why one would return said array of data over the other.
For instance :
router.get('/caseDetail/:id', (req,res) => {
db.caseDetail.findOne({
include : [db.Part,db.Fault,db.Disposition,db.Contact,db.Site]
}).then((response) => {
res.json(response);
}).catch((error) => {
console.table([stack.error,stack.id,error])
})
})
The above route returns an array of data while the following returns just an object
router.get('/caseDetail/:caseName', (req,res) => {
db.caseDetail.findAll({
include : [db.Part,db.Fault,db.Disposition,db.Contact,db.Site],
where : {
caseName:{
[Op.like]: req.params.caseName}
}
}).then((response) => {
console.log(response);
res.json(response)
}).catch((error) => {
console.log(error);
})
})
-------------------------- For context----------------------------
I've enacted this method multiple times, even in other script files, but I haven't been required to parse data in this manner, is something out of shape here that im over looking? Am I missing a JSON.parse(); here? Github
try {
const items = await axios.get(`/api/caseDetail/:caseName` + caseName);
console.log(items.data);
$tbody.empty()
items.data.forEach((item) => {
console.log(item);
Returned Results
{id: 2, caseName: "1 - Fenway Park - 1", createdAt: "2021-07-27T18:13:55.000Z", updatedAt: "2021-07-27T18:13:55.000Z", UserId: 1, …}
Error Message
TypeError: items.data.forEach is not a function
at callSearchResults (searchInventory.js:29)
If I understand you correctly and this is the result that you receive from your request:
{id: 2, caseName: "1 - Fenway Park - 1", createdAt: "2021-07-27T18:13:55.000Z", updatedAt: "2021-07-27T18:13:55.000Z", UserId: 1, …}
Then you would need to take the entries out of it and iterate over them like so:
for (const [key, value] of Object.entries(items)) {
console.log(`${key}: ${value}`);
}
Or like this:
Object.entries(items).forEach(([key, val]) => console.log(key, val));
forEach() is designed for arrays but you can typecast collections and objects into arrays like this...
var I=[...items];
var D=[...items.data]
Now you should be OK, try...
I.data.forEach((item) => {}
D.forEach(() => {}

Angular - Observer map not working as intended

I'm trying to fetch data from my backend, creating a class object for each item I get
getRankingList(type: RankingListType, page: number) {
let params = new HttpParams().set("pid", String(page)).set("limit", String(5));
return this.http.get(`http://127.0.0.1:3333/ranking/player/all`, { params })
.pipe(
map(item => new RankingGuild(item['guild'], item['name'], item['country'], item['honor'], item['RawKey']))
);
}
The data I'm receiving from the backend looks like this:
[
{
"RawKey": "1",
"honor": 0,
"guild": "Test",
"name": "test",
"country": 1
},
{
"RawKey": "2",
"honor": 0,
"guild": "Test2",
"name": "test2",
"country": 1
}
]
But instead of iterating through the object, "item" is the object itself, meaning there is only one iteration returning the object that I had in the first place, rather than its entries. I've been searching for hours to find a solution, but it seems like this is the correct way to do it, not sure why it doesn't work.
This is because the RxJS map operator and JavaScript's Array.map() are 2 different things altogether. You should read up on their differences.
In short, the RxJS map operator allows you to apply a given project function to each value emitted by the source Observable, and emit the resulting values as an Observable. On the other hand, the Array.map() method merely creates a new array with the results of calling a provided function on every element in the calling array.
If you want to map the value returned by the response from the HTTP request, I believe this is what you should be doing instead.
getRankingList(type: RankingListType, page: number) {
let params = new HttpParams().set("pid", String(page)).set("limit", String(5));
return this.http.get(`http://127.0.0.1:3333/ranking/player/all`, { params })
.pipe(
map(response => response.map(item => new RankingGuild(item['guild'], item['name'], item['country'], item['honor'], item['RawKey'])))
);
}
Then, on your component itself, you may subscribe to the method to return the actual values itself.
getRankingList.subscribe(res => {
// do the rest
})
The rx map operator is not the array map operator. The array map transforms items in an array, the rx map transforms items in a stream, and the item in the stream in this case is an array. Do this:
return this.http.get(`http://127.0.0.1:3333/ranking/player/all`, { params })
.pipe(
map(items => items.map(item => new RankingGuild(item['guild'], item['name'], item['country'], item['honor'], item['RawKey'])))
);
Use the array map inside your rx map.

React - Create objects from API call and store in one big object

I have a program that uses Axios to get data with API calls. I want to store the result as a object in my this.state.matrixDictionary variable. but everytime i make another API call the previous object gets overwritten. I want to create something like this
this.setState({
matrixDictionary: {
[0]: result,
}
})
Then next time i make another api call to get other result i want it to be like this:
this.setState({
matrixDictionary: {
[0]: result,
[1]: result,
}
})
But i dont want to add the [1] manually, i want it to be created depending on how many times i make the API call to store the objects. If i make 5 calls then the object should be now [0],[1],[2],[3],[4] so i can easily keep track of the objects and change their values later.
How is this best achieved?
fetchDataAPI(APIUrl){
this.setState({ isLoading: true });
console.log("Fetching from: " + APIUrl);
return axios.get(APIUrl,{
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
})
.then(result => {
this.setState({isLoading: false});
console.log(result.data);
return result.data;
})
.catch(error => {
this.setState({error, isLoading: false })});
}
UPDATE
I used the fix from Roman Batsenko, Next question is how do I then change a property in that object and put it back in setState.
I guess good practice is to use JS Spread syntax for that like ...state.
It depends on the format of answer from your API but I think it would be not so hard to achieve this with:
axios.get(APIUrl,{
/* ... */
})
.then(result => {
this.setState({
isLoading: false,
matrixDictionary: [...this.state.matrixDictionary, result.data]
});
})
make an array of object in your intial state like
this.state = {
matrixDictionary: []
}
and when you call your api push your response object in array so that will store always in another index and finally you make array of objects.
this.setState({ matrixDictionary: result.data});
it may help you.
Why not save the objects in an array, so you can have them in order:
in the constructor:
this.state = {
matrixDictionary: []
}
in your API call:
this.setState(prevState => ({
values: prevState.matrixDictionary.concat(result.data),
}));
You can access them like this:
this.state.matrixDictionary[0] // your first api call
this.state.matrixDictionary[1] // your second api call
this.state.matrixDictionary[2] // your third api call

Updated setState Array from fetch request

I feel like this is a dumb question but I can't find the answer.
Currently I have state:
this.state = {
jsonReturnedValue: []
}
I do a fetch request and get an array of data:
componentDidMount() {
fetch('http://127.0.0.1:8000/api/printing/postcards-printing')
.then(response => response.json())
.then(json => {
this.setState({ jsonReturnedValue: [...this.state.jsonReturnedValue, json.printCategory.products] }, () => console.log(this.state));
});
}
This pushes the array pulled from my fetch request but it creates this:
jsonReturnedValue
[0]Array
[3] Array <--- the array I'm wanting is nested in the original array.
What I need is
jsonReturnedValue
[3]Array
I need my fetch response not to be nested in the already made array.
I see it being one of two issues.
Option 1: [...this.state.jsonReturnedValue, ...json.printCategory.products] Note the spread operator on the second index. I think it's this one!
Option 2: We should see the response body structure but it may be that you need to select a lower-level property on the response. For example, json.data.printCategory.products instead of json.printCategory.products.
You're so close:
this.setState({ jsonReturnedValue: [...this.state.jsonReturnedValue, ...json.printCategory.products] }
You want to concatenate those arrays, but what you were doing (with out the second spread operator) was just adding an array as the item item of another.
Spread both of the arrays you want to concatenate:
this.setState({
jsonReturnedValue: [
...this.state.jsonReturnedValue,
...json.printCategory.products,
],
}, () => console.log(this.state));
Or use Array#concat:
this.setState({
jsonReturnedValue: this.state.jsonReturnedValue
.concat(json.printCategory.products),
}, () => console.log(this.state));
Or if you wanted to replace rather than concatenate:
this.setState({
jsonReturnedValue: json.printCategory.products,
}, () => console.log(this.state));

Categories