I have this code below:
let courses = '';
fetch(link)
.then(function(response) {
return response.json();
}).then(function(json) {
courses = json;
}).catch(function(ex) {
console.log('parsing failed', ex);
});
Using console.log(courses) prints out ''.
How do I set it to the retrieved json?
The fetch method is asynchronous, essentially, you will only have access to the json content in the courses variable after the fetch promise resolves. Try doing the following:
function synchronousCode(courses) {
console.log('courses', courses); // output json courses
}
fetch(link)
.then(function(response) {
return response.json();
})
.then(synchronousCode)
.catch(function(ex) {
console.log('parsing failed', ex);
});
One of the benefits of using the Fetch API is that you can neatly chain your methods instead of just having one "synchronousCode" function. Here's an example:
function asynchronouslyAnalyze(courses) {
return new Promise(function(resolve, reject) {
setTimeout(function () { resolve(courses) }, 1000);
});
}
function parse(courses) {
// do something with courses
return courses;
}
function print(courses) {
console.log('courses', courses); // output courses json
}
function toJSON(response) {
return response.json();
}
fetch(link)
.then(toJSON)
.then(asynchronouslyAnalyze)
.then(parse)
.then(print)
.catch(function(ex) {
console.log('parsing failed', ex);
});
I hope that helps!
Related
I'm attempting to query an API which responds with a ReadableStream of XML.
The code below uses a recursive Promise. Recursive because it sometimes doesn't decode the stream in a singular iteration and this is whats causing my headache.
While I'm successfully fetching the data, for some reason the decoding stage doesn't complete sometimes, which leads me to believe it's when the stream is too large for a single iteration.
componentDidMount() {
fetch("http://thecatapi.com/api/images/get?format=xml&size=med&results_per_page=9")
.then((response) => {
console.log('fetch complete');
this.untangleCats(response);
})
.catch(error => {
this.state.somethingWrong = true;
console.error(error);
});
}
untangleCats({body}) {
let reader = body.getReader(),
string = "",
read;
reader.read().then(read = (result) => {
if(result.done) {
console.log('untangling complete'); // Sometimes not reaching here
this.herdingCats(string);
return;
}
string += new TextDecoder("utf-8").decode(result.value);
}).then(reader.read().then(read));
}
I think that the next iteration was sometimes being called before the current iteration had completed, leading to incorrectly concatenation of the decoded XML.
I converted the function from sync to async and as a regular recursive method of the component rather than a recursive promise with a method.
constructor({mode}) {
super();
this.state = {
mode,
string: "",
cats: [],
somethingWrong: false
};
}
componentDidMount() {
fetch("http://thecatapi.com/api/images/get?format=xml&size=med&results_per_page=9")
.then( response => this.untangleCats( response.body.getReader() ) )
.catch(error => {
this.setState({somethingWrong: true});
console.error(error);
});
}
async untangleCats(reader) {
const {value, done} = await reader.read();
if (done) {
this.herdingCats();
return;
}
this.setState({
string: this.state.string += new TextDecoder("utf-8").decode(value)
});
return this.untangleCats(reader);
}
I'm creating a new register form an app with Ionic and using ASP.Net(C#) as my API.
I want to check if user exists when the input blur event is activate.
The problem is that my code isn't waiting till the server returns a value to continue.
What am I doing wrong? Is there a way to do that?
THIS IS MY API CODE:
[HttpGet]
public JsonResult verifyEmail(string email)
{
var result = Domain.Repository.UserController.Find(email:email);
if (result != null)
{
return Json(new { erro = true, message = "Email already registered!" }, JsonRequestBehavior.AllowGet);
}
else
{
return Json(new { erro=false,message = "Email is valid!" },JsonRequestBehavior.AllowGet);
}
}
I CREATED A PROVIDER TO MAKE THE HTTP REQUEST(authProvider):
getData(data,func)
{
return new Promise( (resolve,reject)=>{
this.http.get(apiUrl+func, {params:data})
.subscribe(
res=>{
resolve(res.json());
},
async (err)=>{
reject(err);
});
});
}
AND HERE IS MY register.ts code:
validate()
{
let validEmail;
validEmail= this.checkEmail();// I WANT THAT the "validEmail" receives returned value before continue.
return true;
}
AND THE LAST THING IS MY FUNCTION THAT WILL CALL THE PROVIDER:
checkEmail()
{
return this.authService.getData({email:this.model.email},"Account/verifyEmail").then((result)=>{
let response = <any>{};
response=result;
if(response.erro)
{
return response.message
}else
{
return true
}
},(err)=>{
this.toastService.presentToast("ERROR:"+err,"bottom",undefined,"toast-error");
});
}
Thanks in advance..
getData(data,func)
{
this.http.get(apiUrl+func, {params:data})
.map(res => {
return res.json();
})
.toPromise();
}
or with async/await
async getData(data,func)
{
let result = await this.http.get(apiUrl+func, {params:data})
.toPromise();
return result.json();
}
Now for the validate function:
async validate()
{
let validEmail;
await this.checkEmail();
return true;
}
Point is you cant jump from a sync function to an async or vice versa.
Validate needs to return a promise/observable because it is executes asynchronous functions.
I'm trying to use d3.json() inside of a function to return data Spotify's API given an artist ID (such as 5K4W6rqBFWDnAN6FQUkS6x), but I can't figure out how to effectively return the data. The function looks like
// Get artist's related artist's information
function relatedArtists(id){
var jsonPromise = new Promise(function(resolve, reject) {
// Async JSON request
d3.json('https://api.spotify.com/v1/artists/' + id + '/related-artists', function(error, data){
if(error) reject(error);
resolve(data.artists);
});
});
jsonPromise.then(function(success) {
console.log(success);
//return(success) //doesn't work
});
jsonPromise.catch(function(error){
console.error(error);
});
}
I've tried creating a variable within the function and then modifying it
function relatedArtists(id){
var testVar = 'hello';
var jsonPromise = new Promise(...{
// Async JSON request
d3.json(...)
});
jsonPromise.then(function(success) {
testVar = success;
});
return(testVar);
}
But testVar remains 'hello', despite my best efforts. I've done some reading about scope and promises, but am happy to do more if there's some core mechanic of either that I'm not understanding. Thanks for reading!
The response will never be available in your calling code due to asynchronous nature of requests. You can use Promises (as supposed by Alexander T. and you, good choice in many cases!) but d3.queue does a good job, too. In my snippet you can see how to run code with the results of multiple requests.
function buildRelatedArtistUri(id) {
return 'https://api.spotify.com/v1/artists/' + id + '/related-artists';
}
d3.queue()
.defer(d3.json, buildRelatedArtistUri('5K4W6rqBFWDnAN6FQUkS6x'))
.await(function(error, data) {
// data and data.artists are available in this functionâs scope only
console.log(data.artists);
});
d3.queue()
.defer(d3.json, buildRelatedArtistUri('5K4W6rqBFWDnAN6FQUkS6x'))
.defer(d3.json, buildRelatedArtistUri('3nFkdlSjzX9mRTtwJOzDYB'))
.await(function(error, data1, data2) {
// this function will be called once both functions have finished
console.log(data1.artists, data2.artists);
});
<script src="https://d3js.org/d3.v4.min.js"></script>
You can return Promise and use relatedArtists function like so
function relatedArtists(id) {
return new Promise(function(resolve, reject) {
d3.json('https://api.spotify.com/v1/artists/' + id + '/related-artists', function(error, data) {
if (error) {
reject(error);
} else {
resolve(data.artists);
}
});
});
}
relatedArtists('5K4W6rqBFWDnAN6FQUkS6x')
.then(function (data) {
console.log(data);
})
.catch(function (error) {
console.log(error);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
In this case, you can not assign the value to testVar, because d3.json is the asynchronous method and that means that d3.json can be done after code execution.
I have a function, it has a $http.post for login purpose. If success, another $http.post will call a php file that fetches data from database. The problem is that, when I am trying to load the data from localStorage it returns me null. Why is it so?
$scope.loginUser = function ()
{
var data =
{
username: $scope.loginInfo.username,
password: $scope.loginInfo.password
}
$http.post("endpoints/login.php", data).success(function(response)
{
if(response==="ERROR")
{
//DONT DO ANYTHING
}
else
{
localStorage.setItem("token", JSON.stringify(response));
console.log("loginController: name is this " + localStorage);
fetchDataFunction(data);
$state.go("application");
//$state.go("application", result);
}
}).error(function(error)
{
console.error(error);
});
}
fetchDataFunction = function(data)
{
$http.post("endpoints/fetchData.php", data).success(function(response)
{
localStorage.setItem("data", JSON.stringify(response));
}).error(function(error)
{
console.error(error);
});
}
You can return the $http.post, which will return a promise, and then all your code will work in the correct order:
$scope.loginUser = function () {
login($scope.loginInfo).then(function (response) {
localStorage.setItem("token", JSON.stringify(response));
console.log("loginController: name is this " + localStorage.getItem("token"));
fetchDataFunction(data).then(function () {
localStorage.setItem("data", JSON.stringify(response));
console.log(localStorage.getItem("data"));
$state.go("application");
}).catch(function (error) {
console.error(error);
});
}).catch(function (response) {
console.error(error);
});
};
var login = function (user) {
return post("endpoints/login.php", user);
};
var fetchDataFunction = function (data) {
return post("endpoints/fetchData.php", data);
};
var post = function (url, data) {
var deferred = $q.defer;
$http.post(url, data).then(function (response) {
if (response === "ERROR") {
deferred.reject(response);
}
else {
deferred.resolve(response);
}
}).catch(function (error) {
deferred.reject(error);
});
return deferred;
};
Notes:
You will need to make sure you inject $q into your controller along with $http
You should use localStorage.getItem() when recalling information from the global object
You should use then/catch instead of success/error, as these are now depreciated: https://docs.angularjs.org/api/ng/service/$http
I have read about "promise" object and all the ways to get some sort of async call or wait until a http call is done, but I haven't been able to success. This is what I got and what I'm trying to do:
I need to get some json file from my server and use the data from that json in my code (js file) and not only as data for my HTML template.
I have a service that does the call to the json file:
mobilityApp.service('serveiWebservices', function($resource) {
return {
getWS: function($scope) {
var path = 'jsonWS/context.json';
$resource(path).get(function (data) {
console.log(data); //data is printed fine
$scope.returnData = data; //just to test, it doesn't work neither
return data;
});
}
};
});
And from my controler I call it like this:
var data = serveiWebservices.getWS($scope);
console.log(data); //undefined
any idea on how to work with the promise object that the funcion returns and perform actions as soon as it gets the requested data ? i Know that I could set a "success" function but I would like not to use callbacks.
Tnanks in advance !
This should work -
Service:
mobilityApp.service('serveiWebservices', function($http) {
return {
getWS: function() {
var path = 'jsonWS/context.json';
return $http.get(path, function (response) {
console.log(JSON.stringify(response, null, 4));
return response.data;
});
}
};
});
Controller:
serveiWebservices.getWS().then(function(data) {
console.log(JSON.stringify(data, null, 4));
});
If you want to use $resource this should work too -
mobilityApp.service('serveiWebservices', function($resource) {
return {
getWS: function() {
var path = 'jsonWS/context.json';
return $resource(path).get(function (response) {
console.log(JSON.stringify(response, null, 4));
return response; // might just be response, no response.data
});
}
};
});
I was searching for a working solution from hours. thanks #Ross.
This also work , i modified the Ross example , and removed the first return :
mobilityApp.service('serveiWebservices', function($http) {
this.getWS = function() {
var path = 'jsonWS/context.json';
return $http.get(path, function (response) {
console.log(JSON.stringify(response, null, 4));
return response.data;
});
}
this.getWS2 = function() {
var path = 'jsonWS2/context.json';
return $http.get(path, function (response) {
console.log(JSON.stringify(response, null, 4));
return response.data;
});
}
});
If i get a lot of function in this service should i use the Ross example with all the function in the return or this one ? thanks