Accessing and looping through data in Promise [duplicate] - javascript

This question already has answers here:
what is right way to do API call in react js?
(14 answers)
async/await implicitly returns promise?
(5 answers)
Closed 26 days ago.
I have a promise from Fetch that I use to get the list of countries from our API:
async fetchDataFromAPI () {
console.log('fetchDataFromAPI')
let response = await fetch(process.env.NEXT_PUBLIC_BRIDGEMAN_API_URL + '/countries',
{
method: 'GET',
headers: {
'Content-Type': 'application/ld+json',
'Accept': 'application/json'
}
})
let data = await response.json();
return data
}
I call that promise inside of a class component in componentDidMount:
componentDidMount() {
this.setState({countries: this.fetchDataFromAPI()})
}
Then when I pass it to the render function, Like this:
const {
countries
} = this.state
console.log('state countries', countries)
I get the following output in my console:
Promise { <state>: "pending" }
<state>: "fulfilled"
<value>: Array(244) [ {…}, {…}, {…}, … ]
[0…99]
[100…199]
[200…243]
length: 244
<prototype>: Array []
<prototype>: Promise.prototype { … }
All the data is there in the ''. I just dont know how to get at it?
I've tried countries.then((data) => {console.log('data', data)}) but I get the message that countries has no method .then. I've tried countries.map and that is the same error.
How can I loop through and output the data on the page?

Related

How to recursive Promises in a loop and passing argument to another

I've checked other threads on SO but none really answers the questions as each answer ommiting something necessary for my case, and none of it is for Apple Music. Apple API is heavily promise-based and even async/await returns promise instead of response:(
I am trying to get all mine playlists, but Apple imposes offset limit of 25 so I have to do this in batches.
Currently I ended with something like this:
async function getAllP() {
let totalresult =[];
window.music.api.music("/v1/me/library/playlists").then(function(o){
let re = o.data;
totalresult.push(re.data);
if ("next" in re) {
// what to insert here?
} else {
return totalresult;
}
});
}
after many failed attempts to properly creates promises in loop or chaining them. I know I need some recursive function. if the keyword "next" is present in response data, then value of this key is url to fetch another batch of playlist so I need to pass that url to another promise.But I cannot set explicit .then chaining because I don't know how long that chain will be. In my case there is 80 playlists but other users may have different number so what I am struggling with is how to write loop/recursive internal function with proper argument passing to get totalresult at the end and without pyramid of doom
totalresult is an 'upper' variable designed to store all the responses objects.
Update:
for those who wanted how response data looks like (copied from console)
getAllPlaylist()
Promise { <state>: "fulfilled", <value>: undefined }
music.api.music('/v1/me/library/playlists')
Promise { <state>: "pending" }
​
<state>: "fulfilled"
​
<value>: Object { request: {…}, response: Response, data: {…} }
​​
data: Object { next: "/v1/me/library/playlists?offset=25", data: (25) […], meta: {…} }
​​​
data: Array(25) [ {…}, {…}, {…}, … ]
​​​
meta: Object { total: 80 }
​​​
next: "/v1/me/library/playlists?offset=25"
​​​
<prototype>: Object { … }
​​
request: Object { baseUrl: "https://api.music.apple.com", path: "/v1/me/library/playlists", url: "https://api.music.apple.com/v1/me/library/playlists", … }
​​
response: Response { type: "cors", url: "https://api.music.apple.com/v1/me/library/playlists", redirected: false, … }
​​
<prototype>: Object { … }
​
<prototype>: Promise.prototype { … }
music.api.music('/v1/me/library/playlists?offset=25')
Promise { <state>: "pending" }
SOLUTION:
Hope this will solve your issue,
const getAll = async () => {
const totalResult = [];
const getP = async (url) => {
const { data } = await window.music.api.music(url);
const hasMore = "next" in data;
totalResult.push(...data);
if (hasMore) return getP(data.next.url);
};
const url = "/v1/me/library/tracks";
await getP(url);
return totalResult;
};
I am not sure how the response data looks like.
I guess you are looking something like below:
Note: you may handle error yourself.
async function getAllP() {
const totalresult = [];
let url = "/v1/me/library/playlists";
while (true) {
const o = await window.music.api.music(url);
const re = o.data;
totalresult.push(re.data);
if ("next" in re) {
url = re.next.url; // assume there is a url in the next.
continue;
}
break;
}
return totalresult;
}
You can do while(url) and url = re.next.url without ifs and continues and breaks.
#Thomas since when it's possible to write like that? isn't that confusing to read?
async function getAllP() {
const totalresult = [];
let url = "/v1/me/library/playlists";
while (url) {
const { data } = await window.music.api.music(url);
totalresult.push(...data.data);
url = data.next;
}
return totalresult;
}
#Sebastian, is this confusing to read?
While I have an url, do ...
And the concept of truthy and falsy values exists since forever in JS.

There seems to be two forms of the array object in my code, reduce does not work on the one. Any ideas? [duplicate]

This question already has answers here:
How to return many Promises and wait for them all before doing other stuff
(6 answers)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Weird behavior with objects & console.log [duplicate]
(2 answers)
Closed 3 years ago.
I create an array in a VueX action that I, in one case, commit to the VueX state (and then use getter to assign it), and in another case, deliver the array in a promise. There seems to be a difference in the type or form of the arrays, even though they stem from exactly the same array.
The VueX getter probably assigns the array correctly whereas just delivering the array as a promise does not.
For the array where reduce is working (VueX getter assigned), logging the array to the console gives:
Array(3) [ {…}, {…}, {…} ]
And when I open it:
0: Object { track: Getter & Setter, course: Getter & Setter, courseLevel: Getter & Setter, … }
​
1: Object { track: Getter & Setter, course: Getter & Setter, courseLevel: Getter & Setter, … }
​
2: Object { track: Getter & Setter, course: Getter & Setter, courseLevel: Getter & Setter, … }
​
__ob__: Object { value: (3) […], dep: {…}, vmCount: 0 }
​
length: 3
​
<prototype>: Object { … }
The array where reduce is not working in the console:
Array []
and opened:
0: Object { track: "test", course: "test", courseLevel: "Beginner", … }
​
1: Object { track: "Computer Vision", course: "advanced openCV", courseLevel: "Advanced", … }
​
2: Object { track: "Computer Vision", course: "intro to comp vis", courseLevel: "Beginner", … }
​
length: 3
​
<prototype>: Array []
There are some differences and I can't figure out where it comes from.
The array comes from the same object, with the first (working) one pushed to VueX state, then loaded again with a getter, and the second (not working) pushed as a promise.
How do I push an array as a promise such that it has the <prototype>: Object { ... } and Getter & Setter property on all values?
EDIT:
The action that gets dispatched and returns the promise
loadSelfCourses ({ commit, getters }, payload) {
return new Promise((resolve, reject) => {
var uemail = ''
if (payload.commitToState) {
commit('clearSelfCourses')
uemail = getters.user.email
} else {
uemail = payload.email
}
firebase.firestore().collection('userCourses').doc(uemail).collection('userSelfCourses').get()
.then(
querySnapshot => {
var tempSelfCourses = []
querySnapshot.docs.forEach(doc => {
firebase.firestore().collection('selfCourses').doc(doc.id).get()
.then(
promise => {
const data = promise.data()
const currentCourse = {
track: data.track,
course: data.course,
courseLevel: data.courseLevel,
learningGoal: data.learningGoal,
link: data.link,
hoursRequired: data.hoursRequired,
courseID: doc.id,
creatorID: data.creatorID,
registeredUsers: data.registeredUsers,
startDate: doc.data().startDate,
endDate: doc.data().endDate,
status: doc.data().status
}
tempSelfCourses.push(currentCourse)
}
)
})
if (payload.commitToState) {
commit('setSelfCourses', tempSelfCourses)
} else {
resolve(tempSelfCourses)
}
})
.catch(error => {
reject(error)
commit('setLoading', false)
})
})
},
Code that dispatches the action and receives the promise.
this.$store.dispatch('loadListOfUsersForAdmin', { email: this.$store.getters.user.email }).then(data => {
data.forEach(user => {
this.$store.dispatch('loadSelfCourses', { email: user, commitToState: false }).then(loadedCourses => {
const progress = this.allCourseProgress((loadedCourses))
// do some stuff here
})
})
})

Vue.js Can't get the data out of a get request into a variable [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I am running a server that is serving a Vue.js app.
So if I input http://localhost:9999/ into my browser,
the browser gets 4 important files:
post.js, get.js, vue.js and the index.HTML with the vue code.
I got a dynamic ordered list to work where each list element
has a button to add an element and to remove itself as well as
a debug button which outputs some variables to the console.
Now I need to make a get request to my server to get an Array with JSON data
that will create some elements in a second ordered list.
I tried the following but nothing works:
//get("http://localhost:9999/text/1", inputData)
//get("http://localhost:9999/text/1").then(inputData)
//inputData = get("http://localhost:9999/text/1")
This is the content of get.js:
//which is correctly included in the vue.js index.HTML
//<script SRC="get.js"> </script>
function get(url, params) {
// Return a new promise.
return new Promise(function(resolve, reject) {
// Do the usual XHR stuff
var req = new XMLHttpRequest();
req.open('GET', url, true);
req.setRequestHeader('Content-type', 'application/json');
req.onload = function() {
// This is called even on 404 etc
// so check the status
if (req.status == 200) {
// Resolve the promise with the response text
//resolve(req.response);
resolve(JSON.parse(req.response));
}
else {
// Otherwise reject with the status text
// which will hopefully be a meaningful error
reject(req.statusText);
}
};
// Handle network errors
req.onerror = function() {
reject("Network Error");
};
// Make the request
req.send(params);
});
}
After the vue.js method block I call
mounted() {
this.$nextTick(function () {
var inputData=[]
//get("http://localhost:9999/text/1", inputData)
//get("http://localhost:9999/text/1").then(inputData)
inputData = get("http://localhost:9999/text/1")
app.vueData = inputData
console.log(inputData)
console.log(JSON.stringify(inputData))
console.log(';)')
})
}
The Promise has the content but I can't transfer it to the variable.
Promise {<pending>}
__proto__: Promise
catch: ƒ catch()
constructor: ƒ Promise()
finally: ƒ finally()
then: ƒ then()
Symbol(Symbol.toStringTag): "Promise"
__proto__: Object
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: Array(4)
0: {text: "This List"}
1: {text: "was pulled"}
2: {text: "from the"}
3: {text: "server"}
length: 4
__proto__: Array(0)
Since comments get deleted I have to get creative:
#Apal Shah
Thanks for this answer. Your code looks way better than the then() solution.
I got wind of the culprit before reading your solution by adding a lot of console.log()s
console.log('app.vueData vor app.vueData = inputData: ')
console.log(app.vueData)
app.vueData = inputData
console.log('inputData nach Zuweisung: ')
console.log(inputData)
console.log('JSON.stringify(inputData)')
console.log(JSON.stringify(inputData))
console.log(';)')
Console Output:
get block: (index):153
app.vueData vor app.vueData = inputData: (index):156
[__ob__: Observer] (index):157
length: 0
__ob__: Observer {value: Array(0), dep: Dep, vmCount: 0}
__proto__: Array
inputData nach Zuweisung: (index):161
[__ob__: Observer] (index):162
length: 0
__ob__: Observer {value: Array(0), dep: Dep, vmCount: 0}
__proto__: Array
JSON.stringify(inputData) (index):164
[] (index):165
;) (index):167
Download the Vue Devtools extension for a better development experience: vue.js:9049
https://github.com/vuejs/vue-devtools
You are running Vue in development mode. vue.js:9058
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html
(4) [{…}, {…}, {…}, {…}] (index):154
0: {text: "This List"}
1: {text: "was pulled"}
2: {text: "from the"}
3: {text: "server"}
length: 4
__proto__: Array(0)
Thanks a bunch going to test it now.
The solution is:
mounted() {
this.$nextTick(async function () {
console.log('get block: ')
console.log('app.vueData vor app.vueData = get() ')
console.log(app.vueData)
//Get is a deferred / asynchronous process / operation
app.vueData = await get("http://localhost:9999/text/1")
console.log('app.vueData nach Zuweisung: ')
console.log(app.vueData)
console.log('JSON.stringify(app.vueData)')
console.log(JSON.stringify(app.vueData))
})
console.log(';)')
}
The caveat was that async had to go in front of function not mounted or this.$nextTick .
You have created a Promise which resolves the data after the completion of your HTTP request but your code is not waiting for this promise to resolve.
You can do 2 things:
1. Use .then()
2. Use async/await (I prefer this because it looks clean)
If you want to use async/await,
mounted() {
this.$nextTick(async function () {
var inputData=[]
//get("http://localhost:9999/text/1", inputData)
//get("http://localhost:9999/text/1").then(inputData)
inputData = await get("http://localhost:9999/text/1")
app.vueData = inputData
console.log(inputData)
console.log(JSON.stringify(inputData))
console.log(';)')
})
}
In this code, you can see that there is async keyword before the function inside this.$nextTick and await keyword before your get method.
If you want to handle the error, you can always use try/catch block.
try {
inputData = await get("http://localhost:9999/text/1");
} catch (e) {
console.log(e);
}
If you're a fan of .then(), your mounted method would look something like this,
mounted() {
this.$nextTick(function () {
var inputData=[]
get("http://localhost:9999/text/1").then(inputData => {
app.vueData = inputData
console.log(inputData)
console.log(JSON.stringify(inputData))
});
console.log(';)')
})
}

Having an issue with my Vuex getter sending a 0 length Array that has items inside when expanded in the console [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Why does console.log wrongly print an empty array?
(1 answer)
Closed 3 years ago.
I am using Vuex to call a Django API for count data.
state: {
DailyCycleDate: []
},
getters: {
DailyCycleDate : state => {
console.log('Getter')
console.log('Length of Array: '+state.DailyCycleDate.length)
console.log(state.DailyCycleDate)
return state.DailyCycleDate
}
},
mutations: {
DailyCountMutation(state, DailyCount) {
const NewPatientMap = new Map(Object.entries(DailyCount));
let NewList = []
NewPatientMap.forEach((value, key) => {
var NewPatientCycle = value['Current_Cycle_Date']
console.log('inside mutation')
state.DailyCycleDate.push(NewPatientCycle)
});
}
},
actions: {
DailyCountAction ({ commit }) {
axios({
method: "get",
url: "http://127.0.0.1:8000/MonthlyCountByDay/",
auth: {
username: "test",
password: "test"
}
}).then(response => {
commit('DailyCountMutation', response.data)
}).catch((error) => {
console.log(error)
})
}}
And for some reason I am returning an empty array in the console log:
My question is, how did this array become empty? Is there a sync issue going on? I've been working with promises and TimeOut methods and nothing has helped. How am I able to see the data I need to see while the array is 0?
Could there be an object inside of the array? I've also tried changing it into a object and mapping it. Any advice is greatly appreciated!
Thanks,
I should also note that I am needing this data to be in the label field of a ChartJS barchart
export default {
extends: HorizontalBar,
data() {
return{
}
},
mounted () {
/* Need to write the API call for chart data here. */
this.$store.dispatch('DailyCountAction')
this.renderChart({
labels: [this.$store.getters.DailyCycleDate],
datasets: [...]
state.DailyCycleDate.push doesn't update state.DailyCycleDate reference.
You need to update reference of state.DailyCycleDate to make getters re-calculated again
mutations: {
DailyCountMutation(state, DailyCount) {
const NewPatientMap = new Map(Object.entries(DailyCount));
let NewList = []
NewPatientMap.forEach((value, key) => {
var NewPatientCycle = value['Current_Cycle_Date']
console.log('inside mutation')
NewList.push(NewPatientCycle)
});
state.DailyCycleDate = state.DailyCycleDate.concat(NewList)
}
}

How to fetch data Array in Promise [duplicate]

This question already has answers here:
Why does .json() return a promise?
(6 answers)
Closed 6 years ago.
I call API on my react JS app :
result = fetch('http://localhost:5000/cities')
result.then(function(response) {
console.log(response.json());
})
Then output log :
Promise
__proto__ : Promise
[[PromiseStatus]] : "resolved"
[[PromiseValue]] : Array[5]
0: Object
1: Object
2: Object
3: Object
4: Object
length: 5
__proto__: Array[0]
How do I fetch data on Array ?
I need get city name list
The line response.json() returns a promise that resolves to the parsed JSON.
You can simply write
result.then(function(response) {
return response.json();
}).then(function (data) {
console.log(data);
});

Categories

Resources