I have 2 json's which I get on making 2 different API calls.
fetch(`veb/api/roleDetails/${id}`).then(response =>
response.json()
).then(responseJson => {
console.log('responseJson = ' + JSON.stringify(responseJson));
this.setState(() => {
return {
allRoleDetails: responseJson,
}
});
}
).catch(error => console.error('Error:', error))
2nd:
fetch(`/api/api/itemTypes`).then(response =>
response.json()
).then(responseJson => {
console.log('responseJson = ' + JSON.stringify(responseJson));
this.setState(() => {
return {
names: responseJson,
}
});
}
).catch(error => console.error('Error:', error))
in the 1st api call I get itemtypeid from which I have to make the 2nd api call to fetch the name of the typeid.Even if I get a combined json it will be fine
How to do that?Any help will be great.
Thanks
Promise.all is what you need. Basically, what it does is merging a collection of promises into one single promise, and return the resolved values one everything inside the collection done.
Promise.all([
fetch(`veb/api/roleDetails/${id}`).then(response => response.json()),
fetch(`/api/api/itemTypes`).then(response => response.json())
]).then(([allRoleDetails, names]) => {
// allRoleDetails is the resolve of your first promise
// names is the resolve of your second promise
}).catch(err => {
// catch error here
});
More details about Promise.all can be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Related
I have a mocked file mockedfile.html which I am redirecting to locally. My problem is that when I try to extract the HTML from the fetch response, the result does not look exactly like the mocked file. So this is what I do:
fetch('/some-url.html').then(response => {
if (response.redirected) { // this will be true locally
fetch(response.url) // which will then be /mockedfile.html
.then(res => res && res.text())
.then(text => text) // expect this text to be the same as the content inside mockedfile.html, but this is just partly the same
} else {
response && response.text().then(text => text);
}
}
})
What am I missing? Is there a more propper way to solve this?
To get the values outside of your fetch, you need the first .then() return something.
The extra .then() is unnecessary, because it just creates a new promise resolving to the same value.
fetch('/some-url.html')
.then(response => {
if (response.redirected) {
return fetch(response.url)
.then(res => res.text());
}
return response.text();
})
.then(console.log)
.catch(console.error)
You have to add ) to close brace opened at then(
fetch('/some-url.html').then(response => {
if (response.redirected) { // this will be true locally
fetch(response.url) // which will then be /mockedfile.html
.then(res => res && res.text())
.then(text => text) // expect this text to be the same as the content inside mockedfile.html, but this is just partly the same
} else {
response && response.text().then(text => text);
}
});
})
fetch(url).then(result => result.text()).then(yourText => ...);
I'm having trouble understanding the best approach to this.
My goal is to display nested data.
I use fetch on this url - https://horizons-json-cors.s3.amazonaws.com/products.json
which takes me to a page that contains json. inside the json is 3 urls. each url contains the data that I need to get to.
So far, I've accessed the first layer, and now have an array of the item urls. I guess I don't understand how to fetch the data while im inside the outter fetch call.
Here's my code thus far (the result is an array of urls, where each url contains the data I need.) :
componentDidMount() {
console.log('Fetch');
fetch("https://horizons-json-cors.s3.amazonaws.com/products.json")
.then((resp) => (resp.json()))
.then((json) => {
var productUrlArr = [];
for (var i = 0; i < json.length; i++) {
productUrlArr.push(json[i].url);
}
.catch((err) => {
console.log('error', err);
});
}
If you guys could help me out and really walk through how to access the next level of data, I would really, really appreciate it.
You can Fetch Data for Inner URLs this way too,
// 1. Outer Fetch call initiated here
fetch("https://horizons-json-cors.s3.amazonaws.com/products.json")
.then(res => {
return res.json()
})
.then(res => {
// 2. array for storing url's retrieved from response
var urlArray = []
if (res.length > 0) {
// 3. Push url inside urlArray
res.map(data => urlArray.push(data.url))
}
// 4. an array of urls
return urlArray
})
.then(urls => {
// Return an promise which will return "JSON response" array for all URLs.
// Promise.all means “Wait for these things” not “Do these things”.
return Promise.all(urls.map(url => {
// Take url fetch response, return JSON response
return fetch(url).then(res => res.json())
}
))
})
.then(res => {
// Store all objects into array for later use
var objArr = res; return objArr
})
//.then(...)
You have a little error in your code.
It's missing }) before .catch
With it you can use your data in the array.
componentDidMount(){
console.log('Fetch');
fetch("https://horizons-json-cors.s3.amazonaws.com/products.json")
.then((resp) => (resp.json()))
.then((json) => {
var productUrlArr = [];
for (var i = 0; i < json.length; i++) {
productUrlArr.push(json[i].url);
}
console.log(productUrlArr);
}).catch((err) => {
console.log('error', err);
});
}
Hope it helps.
It simple. First get all the url first like you did. Then map and pass it into Promise.all.
fetch("https://horizons-json-cors.s3.amazonaws.com/products.json")
.then((resp) => (resp.json()))
.then((json) => {
Promise.all(json.map(product =>
fetch(product.url).then(resp => resp.text())
)).then(texts => {
// catch all the data
})
}).catch((err) => {
console.log('error', err);
});
I've a promise in Parent class, whenever I call the promise from child class, it is returning the undefined, instead of executing the promise and returning the resul.
import {newsApiKey as APIKEY, newUrl as APIURL} from "./secretToken";
class News{
constructor(){
this.token = APIKEY;
this.url = APIURL;
this.source = 'bbc-news&';
}
topNews(){
const bbcNews = fetch(`${this.url}?source=${this.source}&sortBy=top&apiKey=${this.token}`);
bbcNews.then(response => {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json()
})
.then(json => {
console.log(json.articles);
return json.articles;
})
.catch((err) => {
return err.message;
});
}
}
export { News as default};
CHILD CLASS
import News from "./news";
class StickyNote extends News{
displayNews(){
let bbcNews = super.topNews(); // It is returning only undefined
if (typeof bbcNews != 'undefined') {
console.log(bbcNews); //
}
}
}
topNews never returns anything, so the result of calling it is undefined.
You probably wanted a return here:
topNews() {
const bbcNews = fetch(`${this.url}?source=${this.source}&sortBy=top&apiKey=${this.token}`);
return bbcNews.then(response => {
// ^^^^^^
if (!response.ok) {
throw Error(response.statusText);
}
return response.json()
})
.then(json => {
console.log(json.articles);
return json.articles;
})
.catch((err) => {
return err.message;
});
}
Also note that displayNews will need to use the promise it receives:
displayNews(){
super.topNews().then(articles => {
// ...use articles
});
}
(Normally you'd also have a catch there at the endpoint of consumption, but as you've converted rejections into resolutions...)
Note: That code has a bit of an anti-pattern in it: It converts a rejection into a resolution with an error message. Anything using the promise will never see a rejection, only resolutions with varying return types (whatever json.articles is or a string). In general, it's better to allow rejections to propagate, and handle them at the ultimate point of consumption of the entire chain (displayNews, I believe, in your example). You might transform their content, but not convert them from a rejection into a resolution.
FWIW, I'd probably rewrite that like so:
topNews() {
return fetch(`${this.url}?source=${this.source}&sortBy=top&apiKey=${this.token}`)
.catch(_ => {
throw new Error("network error");
})
.then(response => {
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json();
})
.then(data => { // "data", not "json" -- it's not JSON anymore
return data.articles;
});
}
...which ensures that the caller either gets a resolution with the articles, or a rejection with an Error, so:
displayNews(){
super.topNews()
.then(articles => {
// ...use articles
})
.catch(err => {
// ...show error
});
}
I have a provider service that calls get requests from my API. I then have a listing page whereby you can scroll though many recipes. What I am struggling with is taking the ID of each recipe and passing it to the details page as this needs to be included within.
My service request is for the listing is
loadCategory1() {
var url = "http://api.yummly.com/v1/api/recipes?_app_id=////&_app_key=////";
if (this.Category1) {
return Promise.resolve(this.Category1);
}
return new Promise(resolve => {
this.http.get(url + "&allowedAllergy[]=396^Dairy-Free&allowedAllergy[]=393^Gluten-Free&maxResult=50&start=10")
.map(res => res.json())
.subscribe(data => {
console.log(data);
this.Category1 = data.matches;
resolve(this.Category1);
});
});
}
and I currently have a separate one for my details as well
loadDetails() {
if (this.details) {
return Promise.resolve(this.details);
}
return new Promise(resolve => {
this.http.get('http://api.yummly.com/v1/api/recipe/French-Onion-Soup-The-Pioneer-Woman-Cooks-_-Ree-Drummond-41364?_app_id=//////&_app_key=//////')
.map(res => res.json())
.subscribe(data => {
console.log(data);
this.details = data;
resolve(this.details);
});
});
}
As you can see in the details request i have French-Onion-Soup-The-Pioneer-Woman-Cooks-_-Ree-Drummond-41364 This needs to be dynamic by taking the ID from each recipe. Example is below.
Within each .ts file I have the following
loadRecipes(){
this.apiAuthentication.loadCategory1()
.then(data => {
this.api = data;
});
}
This allows me to call the request.
I'm at the point now where I have no clue what to do so some help would be great.
Your DetailsService can be something like this:
loadDetails(detailsId: string) {
return new Promise(resolve => {
this.http.get('http://api.yummly.com/v1/api/recipe/'+detailsId+'?_app_id=//////&_app_key=//////')
.map(res => res.json())
.subscribe(data => {
console.log(data);
this.details = data;
resolve(this.details);
});
});
}
Navigate to DetailsPage with arguments:
this.navCtrl.push(DetailsPage,{
recipe: recipe
});
And you can call DetailsService inside DetailsPage by using code like this:
loadDetails(){
this.apiAuthentication.loadDetails(this.recipe.id)
.then(data => {
this.details = data;
});
}
When I used SuperAgent I didn't have this problem, but I decided to use Window.fetch polifyl and I met this problem. I see all data was loaded, but it still shows error.
Could your help me identify this error please:
In render() I genereate a list of components based on an obtained list:
render() {
if (this.state.data.list) {
console.log("render: " + this.state.data.list);
var counter = 0;
const list = this.state.data.list.map((item) => {
....
The promise handlers in your screenshot won't work:
.then((json) => console.log('parsed json: ', json))
.then((json) => { this.setState({ data: json }); })
"Take the value from resolving this promise and pass it to console.log. Then, take console.log's return value (which is undefined) and pass it to this.setState."
fetch(url, {
headers: {
'Accept': 'application/json',
},
}).then((response) => response.json()
.catch(err => {
console.err(`'${err}' happened!`);
return {};
}))
.then((json) => {
console.log('parsed json: ', json);
this.setState({ data: json })
})
.catch((err) => { console.log('fetch request failed: ', err) }
)