I'm trying get data from firestore. Connection is ok, data is downloading but with problems.
I'm based on https://firebase.google.com/docs/firestore/query-data/get-data example.
let list = [];
let products = function GetCollection() {
firestore.collection("products")
.get()
.then(function (querySnapshot) {
querySnapshot.forEach(function (doc) {
console.log(doc.id, " => ", doc.data());
list.push(doc.data());
});
$scope.collection = list;
});
}
products();
console.log("test");
After run this code, my list is empty but in console are listed all entries. During debuging i noticed that last line with console.log("test") is executed before all body of GetCollection() function.
This is problem with sync? Can anyone help me?
yes this is expected behavior, console.log("test"); will be executed first. Because part .then(function (querySnapshot is a asynchronous call, what you are passing inside .then is a javascript promise, and that is asynchronous
you should also use handle error as mentioned in below line
.get(some comde). then ( function -- ). catch ( function (error) { console.log("Error getting cached document:", error); } )
for testing purpose, you can use firebase synchronous version of method as well, generally firebase api have corresponding sync version of method, and if I remember correctly those are suffixed with "sync"
Related
I have a few problem while integrating api from OpenWeather.
I can successfully log the response data value from the api. But when i call from another component with .then(), throw me the error.
The following is my api.js call with axios
function getFiveDayForcast(cityName) {
axios.get(`http://api.openweathermap.org/data/2.5/forecast/daily?q=${cityName}&type=accurate&APPID=${apiKey}&cnt=5`)
.then(function(response){
// console.log("response" , response.data);
return response.data;
})}
module.exports= {getFiveDayForecast:getFiveDayForecast}
This is when i call back from my Component
componentDidMount(){
let city = queryString.parse(this.props.location.search).city;
this.makeRequest(city);
}
makeRequest =(city) => {
//set loading false
this.setState(()=> ({loading:false}));
api.getFiveDayForecast(city).then((response) => {
console.log(response)
})
}
And it throw
TypeError: Cannot read property 'then' of undefined
Would be nice if someone can explain in details about it. I am also reading documentation as well. Thanks in advance.
Posting my answer here so more people can see.
Referring to Returning an Axios Promise from function
The complaint is that a function needs to return something in order for the then chain to know what to do. The function preceding the then chain is not returning anything, so the function inside then then chain doesn't know what to do.
Axios takes care of this for the get action, but you aren't directly chaining the get method to then. Instead, you are chaining a method you created, getFiveDayForcast.
You should change getFiveDayForcast(cityName) (btw 'Forecast' is the right spelling) to
function getFiveDayForcast(cityName) {
const request = axios.get(`http://api.openweathermap.org/data/2.5/forecast/daily?q=${cityName}&type=accurate&APPID=${apiKey}&cnt=5`)
.then(function(response){
// console.log("response" , response.data);
return response.data;
})
return request;
}
You need to return the Promise from your Function getFiveDayForcast.
function getFiveDayForcast(cityName) {
return axios.get(`http://api.openweathermap.org/data/2.5/forecast/daily?q=${cityName}&type=accurate&APPID=${apiKey}&cnt=5`)
.then(function(response){
// console.log("response" , response.data);
return response.data;
})
}
I an using Ionic for my app with a connection to Firebase to pull data. I created a promise in a factory to pull data down and thought it should render the data on the screen once it finishes but I'm getting nothing until I touch the screen?
I get no error and the data does indeed come.
Factory:
all: function () {
return new Promise ((resolve, reject) => {
firebase.database().ref('desks').once('value').then(snapshot => {
let desks = []
snapshot.forEach((child) => {
desks.push(child.val());
});
resolve(desks)
});
});
}
Calling the Factory:
Office.all().then(function (data) {
console.log(data);
$scope.officeList = data;
});
I feel I'm calling it wrong or else there is an Ionic method that I can't seem to find.
How will I be able to have the data render once it finishes the request?
Thanks in advance
ES6 promises are not integrated with the AngularJS framework. Use $q.when to convert ES6 promises to AngularJS promises. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc.
all: function () {
̶r̶e̶t̶u̶r̶n̶ ̶n̶e̶w̶ ̶P̶r̶o̶m̶i̶s̶e̶ ̶(̶(̶r̶e̶s̶o̶l̶v̶e̶,̶ ̶r̶e̶j̶e̶c̶t̶)̶ ̶=̶>̶ ̶{̶
var es6promise = firebase.database()
.ref('desks').once('value')
.then(snapshot => {
let desks = []
snapshot.forEach((child) => {
desks.push(child.val());
});
̶r̶e̶s̶o̶l̶v̶e̶(̶d̶e̶s̶k̶s̶)̶
return desks;
});
return $q.when(es6promise);
}
Also avoid using Promise(resolve,reject to create new promises. Instead use the promise returned by the .then method. It returns a new promise which is resolved or rejected via the return value of the successCallback, errorCallback (unless that value is a promise, in which case it is resolved with the value which is resolved in that promise using promise chaining).
For more information, see You're Missing the Point of Promises.
I am new to MEAN environment and not an expert in using promises. I am confused how to achieve this behaviour using promise.
my router method makes call to service method which has promise chained to qyery DB and returns results. I want to send back those results to router so I can send to front end. Thats there problem lies and I get undefined.
Router.js:
myrouter('/api/getDatafromDB',(req,res){
results =getSQLResults();
res.send(results); //want to achieve that.
}
SQLServiceFile.js :
//Db connection code defined in separate js file - dbConfig.js and
//imported in connection object
getSQLResults=function(){
connection.connect().then( //promise1
function(recordset){
request.query('select * from xyz') //promise 2
.then(
//recordset fetched fine here and want to pass to router.
rec= recordset['recordset']; //basically want to pass back rec.
console.log(rec);
connection.close();
).catch(function(err){
//error handling}
connection.close();)
}
).catch(//error handling code);
}
I tried different variations but did not work. Now I think somewhere I read that I need to pass back callback again in promise or something like that. I don't know. But I think If I change my code to use callbacks and not promise, it would work Or If I put back sql query code in router.
I want to keep code structured like this so please suggest right method.
Your code is syntactically wrong. Maybe the below piece of code will help you, it's the right way to use promises and async programming. The pattern used below is known as .then chaining. We can chain multiple .then to achieve a synchronous pattern in js.
.then and .catch only accept a function as an argument.
myrouter('/api/getDatafromDB', (req,res) => {
getSQLResults()
.then( result => res.send(results) )
.catch( err => ErrorHandler(err) )
}
SQLServiceFile.js :
//Db connection code defined in separate js file - dbConfig.js and
//imported in connection object
function getSQLResults() {
return connection.connect()
.then( function() {
return request.query('select * from xyz')
})
.then( function(recordset) {
connection.close();
return recordset['recordset'];
})
.catch( function(err) {
connection.close();
throw err; // it can be done so that you can handle the errors in myRouter
});
}
I am trying to get data from server with service function that I found in a template reactjs project. I do recieve a perfectly fine anwser from the server, I can see the arrays are ok while still in the service, but not when handed over to the component that called for it in the first place. At the component I get a promise object, which has the values (I have seen them in console) but I can't access them. What am I missing?
My component has following function:
calculate(dict) {
var results = Service.calc(dict)
.catch((err) => {
var errResp = JSON.parse(err.response);
console.log(errResp);
this.setState({responseErrors: errResp});
});
this.setState({results:results._handler});
}
When I printed the results in to console I saw the Promise object, inside _handler.handler was a value array with my values but I couldn't use them. The error appeared when accessing the results._handler.handler: undefined.
The called service looks like this:
class Service {
calc(dict) {
return this.handleCalculate(when(request({
url: UserConstants.URL,
method: 'POST',
type: 'json',
data: dict
})));
}
handleCalculate(calcPromise) {
return calcPromise.then(
function(data) {
console.log(data); //Success
return data;
}
)
}
Meanwhile I use ajax call directly in the component instead of the service. But I understand that is bad practice, how can I get this right?
Hi basically you put setState in the wrong place. (It sets state right away without waiting for result getting resolved). It should look like this
calculate(dict) {
var results = Service.calc(dict)
.then(results => {
this.setState({results: results});
})
.catch((err) => {
var errResp = JSON.parse(err.response);
console.log(errResp);
this.setState({responseErrors: errResp});
});
}
testAngular(); //**(1º)**
function testAngular() {
var uri = 'some_webmethod_url';
var data = {
"key": "anything"
};
var res = $http.post(uri, data);
res.then(function (data) {
console.log(data); //**(2º)**
});
console.log(data); //**(3º)**
}
console.log(data); //**(4º)**
The actual sequence is 1º -- 3º -- 4º -- 2º; Why?
And more importantly, how can I make this in that sequence? (1º -- 2º -- 3º -- 4º)
Since the 'then' is a callback and called asynchronously when the response from the server becomes available (after the POST request is completed). So the statement console.log(data); //**(2º)** will be executed only after the response is received but rest of other processing will continue.
If you want the order that you mentioned, you will have to make those statement as part of the callback. The other option is to make the callbacks synchronous which is not supported out of the box by Angular JS but you can look into the source code and make changes. This SO post might help you in that https://stackoverflow.com/questions/13088153/how-to-http-synchronous-call-with-angularjs
Or a small hack as mentioned in other SO post might help you AngularJs: Have method return synchronously when it calls $http or $resource internally though it's not recommended.
testAngular(); //**(1º)**
function testAngular() {
var uri = 'some_webmethod_url';
var data = {
"key": "anything"
};
var res = $http.post(uri, data);
res.then(function (data) {
console.log(data); //**(2º)**
console.log(data); //**(3º)**
console.log(data); //**(4º)**
});
}