I've got this code:
var me = Restangular.one('object', 1).get({params:params});
me.then(function (data) {
$scope.me = data;
$scope.loadsubobject();
});
$scope.loadsubobject = function () {
$scope.me.getList("subobject")
.then(function(subobject) {
//the code never gets here
console.log('loaded subobjects', subobjects);
$scope.subobjects = $scope.subobjects.concat(subobject.results);
if (data.next){
$scope.next = data.next;
}
},function(response){
console.log('Error with response:', response.status)
});
when I try to debug the code It seems that after calling the $scope.me.getList("subobject")It returns to the first thenand never getting to the second then, the one that actually process the subobjects I need.
Any clue out of call back hell?
I verified that the server does return the correct answer
How can I fix that? be glad for help with this
turned out to be a completely different issue, the json returned wasn't "flat", so I need to use a responseExtractor as explained here
Related
I'm new to both react and firebase. I'm trying to get a string of file names (just as a continuous string for right now) from a particular folder in the firebase storage bucket. My code is as follows:
getFilesList(){
var toReturn="";
toReturn+="Testing";
var storage = firebase.app().storage(".....");
var storageRef = storage.ref();
var listRef = storageRef.child("/slides/1HdDPbTarLBxzllDlA3H/Lecture1/");
listRef.listAll().then(function(result) {
result.items.forEach(function(imageRef) {
toReturn+=this.getImageString(imageRef);
});
}).catch(function(error) {
toReturn+="error1";
});
return toReturn;
}
getImageString(imageRef) {
var toReturn="T1";
imageRef.getDownloadURL().then(function(url) {
var toReturn=url.toString();
}).catch(function(error) {
toReturn+="error2";
});
return toReturn;
}
I'm not getting any errors, but the return string is blank (aside from the 'Testing' prefix). The folder has about 20 jpg files, but it seems as though it isn't seeing that they are there. I did some research online about it, but I'm still not sure why my code isn't working. Please help me to know why this isn't working?
Thank you,
Jared
This isn't a problem with your framework, it's a problem with asynchronous code.
See, toReturn will eventually update with the results of that function call. The problem is that the caller of this function receives the array immediately, before any of the code in .then has a chance to touch it.
Even if the promise resolves instantly, the code above it will have already executed. Promises get put on a queue where the top item only executes after the current synchronous code has finished.
What getFilesList needs to do is return a Promise that the caller can then attach to in order to specify its own behaviour:
getFilesList(){
var toReturn="";
toReturn+="Testing";
var storage = firebase.app().storage(".....");
var storageRef = storage.ref();
var listRef = storageRef.child("/slides/1HdDPbTarLBxzllDlA3H/Lecture1/");
listRef.listAll().then(function(result) {
result.items.forEach(function(imageRef) {
toReturn+=this.getImageString(imageRef);
});
return toReturn;
}).catch(function(error) {
toReturn+="error1";
return toReturn;
});
And in the caller:
getFilesList.then(filesList => console.log(filesList))
In my controller i am calling this function in my service. idservice.getid()
I am testing it by printing it to console using console.log(idservice.getid())
and it returns undefined the first time, but after that if i call it again it returns the value.
I understand this is a async issue but im not sure how to make this work.
my service is below:
function idservice (userauth) {
var id;
this.getid = function() {
userauth.currentUser().then(function(user) {
id = user.id;
});
return id
}
}
How can i make it so that on the first call it doesnt return undefined? Is this a async issue?
This's happening because inside userauth currentUser() method you're making http call and response ('user.id') is yet not available. You can return the userauth.currentUser() call inside getid() method & also return id inside its success callback then. So your service method should look like
function idservice (userauth) {
var id;
this.getid = function() {
return userauth.currentUser().then(function(user) {
id = user.id;
return id;
});
}
}
And inside controller you should handle it like
idservice.getid().then(function(response){
$scope.id = response;
});
Here's small example of your requirement: https://plnkr.co/edit/bEjR9e179aRPfJiaQpei?p=preview
I've encountered this problem today, seems like if you request some data from the server and you assign it to a variable THEN you try to print it, it will show undefined on the first call, I think this is not something it should happen since you are trying to print it AFTER you got the information, but whatever.
I fixed it by removing that variable, just got the data then printed it.
I think this will solve your problem (the OP's last login is 2 years ago, but maybe it will help somebody else that encountered this and didn't found a useful answer?)
function idservice (userauth) {
this.getid = function() {
return userauth.currentUser().then(function(user) {
return user.id;
});
}
}
This will return the user.id as it is, it will not store it in a variable, you want it to be stored in a variable ? Store it, but don't print that variable, something like this :
function idservice (userauth) {
var id;
this.getid = function() {
return userauth.currentUser().then(function(user) {
id = user.id;
return user.id;
});
}
}
This worked for me (or at least the logic behind it worked).
Got the following code:
On AngularJS client:
var getDocs = function() {
return $http.get('/api/docs/list')
.then(function(result) {
return result.data; // bookmark1 line
});
}
On Node.Js BE:
function getDocs() {
return Doc.find({}).exec()
.then(function success(docs) {
return res.send(docs);
});
}
Works perfectly.
When I change the first line in getDocs() to
return Doc.find({}).select('-field1 -field2').exec()
I see the docs after the query execution without the fields (as expected) but for some reason The http is pending and chrome debugger is not stopping on the success callback of the client (bookmark1 line).
Edit:
Changed to
return Cv.find({}).select('-field1 -field2').exec(function success(err, cvs) {
return res.send(cvs);
});
Got the following error in client:
Solution:
Well It turn out I had another field which depends on field1
docSchema.virtual('field3').get(function () {
return this.field1.toString("base64");
});
It fails and for some reason it didnt appear on my IDE.
I Added a null check and that solve the problem.
Not sure if I should remove this question or maybe it has value for other people. Feel free to say what you think.
I am making $http request to multiple environment and processing after I get all the responses. I am using the code below:
$q.all(Object.keys($rootScope.envs).map(request)).then(function(res){
var results = {};
for (var env in res) {
results[env] = res[env].data;
}
}, function(err){
console.error(err);
});
function request(env) {
return $http.get(callService.getDomainUrl()+'/'+$rootScope.envs[env]+ '/hosts.json');
}
The above code works fine, but the results object looks like below:
{
0: {data:{}},
1: {data:{}},
2: {data:{}},
3: {data:{}}
}
I want the corresponding response for each key and the results should be like
{
env1: {data:{//data for env1}},
env2: {data:{//data for env2}},
env3: {data:{//data for env3}},
env4: {data:{//data for env4}},
}
How to map the corresponding response to the key? Please let me know how to get this as this is asynchronous request. Should I have something from the API to know which env the API is coming from?
I think the simplest way would be to push the result handling into the request function, that way you still have the 'env' value in scope.
var results = {};
$q.all(Object.keys($rootScope.envs).map(request)).then(function(res){
// Do something with 'results' here.
}, function(err){
console.error(err);
});
function request(env) {
return $http.get(callService.getDomainUrl()+'/'+$rootScope.envs[env]+ '/hosts.json')
.then(function(res) { results[env] = res.data; return env; });
}
Another option would be to replace my return env with return [env, res.data] and then you can go back to creating the results object as in your original code.
The important thing here is to remember you can handle the $http.get promises individually as well as using the promises from the call to then in $q.all.
I was planning on making a service that caches server response data in AngularJS and this is what I did:
function addDataCachingServiceToModule(module) {
module.factory('myDataCaching', function ($q, itemRepository) {
var categoriesWithNewItems = undefined;
function getCategoriesWithNewItems(date) {
var deferred = $q.defer();
if (!categoriesWithNewItems) {
return itemRepository.getCategoriesWithNewItems(date)
.then(function (res) {
if (res.data.Data.Success) {
categoriesWithNewItems = res;
deferred.resolve(res);
} else {
deferred.reject(res);
}
});
} else {
deferred.resolve(categoriesWithNewItems);
}
return deferred.promise;
}
function resetCategoriesWithNewItems() {
categoriesWithNewItems = undefined;
}
return {
getCategoriesWithNewItems: getCategoriesWithNewItems,
resetCategoriesWithNewItems: resetCategoriesWithNewItems
};
});
}
To my shock, it seems that while this works normally, when I try to use it like this:
myDataCaching.getCategoriesWithNewItems(date)
.then(function(res2) {
// res2 = undefined here !!!
});
..I get undefined instead of the data that I pass in in deferred.resolve(res);.
I have debugged this and it calls the 1st deferred.resolve(res); in my service with valid data, but in my then() I get undefined instead.
It never passes through any of the other resolve()/reject() calls.
Does anyone have any idea what's wrong here?
So, Anant solved your missing return issue. Let's discuss how you won't have it any more in the first place :)
Promises chain, your current code has the deferred anti pattern which we'd rather avoid. You're creating excess deferred which you shouldn't. Your life can be a lot easier:
function addDataCachingServiceToModule(module) {
module.factory('myDataCaching', function ($itemRepository) {
var cats = null; // prefer null for explicit lack
function getCategoriesWithNewItems(date) {
// are we sure we don't want to cache by date?
return cats = (cats || itemRepository.getCategoriesWithNewItems(date))
}
function resetCategoriesWithNewItems() {
categoriesWithNewItems = null;
}
return {
getCategoriesWithNewItems: getCategoriesWithNewItems,
resetCategoriesWithNewItems: resetCategoriesWithNewItems
};
});
}
So, what did we do here:
Cache the promise and not the value to avoid race conditions. In your original version making multiple requests before the first one returned and then updating the cache multiple times which would have made deleting not work.
Avoid creating an excess deferred, this is faster and cleaner too.