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))
Related
I have this problem with kinvey backend,
I'm trying to fetch data from my collection but it doesn't work for me. here is my code :
var query = new $kinvey.Query();
query.equalTo('_id', '5909e8084c68b1ef74fa4efc');
var dataStore = $kinvey.DataStore.collection('User1Bases', $kinvey.DataStoreType.Network);
var stream = dataStore.find(query);
stream.subscribe(function onNext(entity) {
// ...
}, function onError(error) {
// ...
}, function onComplete() {
//...
});
Can you help me please
If you let run the code you have posted then consider four things:
Make sure you have Kinvey implemented:
<script src="https://da189i1jfloii.cloudfront.net/js/kinvey-html5-sdk-3.10.2.min.js"></script>
Make sure you have initialized the Kinvey service before:
// Values shown in your Kinvey console
Kinvey.init({
appKey: '<your_appKey>',
appSecret: 'your_appSecret'
});
Make sure you are logged in with a user that has the rights to read your collection (should be fine using the All Users role (default)):
var promise = Kinvey.User.login('<username>', '<password>')
.then(function() {
console.log ("You are logged in");
})
.catch(function(error) {
console.log (error);
});
Output the return result to see whats coming back. To make sure you do the query AFTER successful login, paste you query inside the .then function of login.
I'm not sure if your query is valid unter 3.x since a lot has changed and I'm not working with older Kinvey versions.
So that all together would look like this:
// Initialize Kinvey
Kinvey.init({
appKey: '<your_appKey>',
appSecret: 'your_appSecret'
});
// Login with already registered user
var promise = Kinvey.User.login('<username>', '<password>')
.then(function() {
console.log ("You are logged in");
// Your query
var query = new $kinvey.Query();
query.equalTo('_id', '5909e8084c68b1ef74fa4efc');
var dataStore = $kinvey.DataStore.collection('User1Bases', $kinvey.DataStoreType.Network);
var stream = dataStore.find(query);
stream.subscribe(function onNext(entity) {
// Output of returning result
console.log (entity);
// ...
}, function onError(error) {
// ...
}, function onComplete() {
//...
});
})
.catch(function(error) {
console.log (error);
});
There are now three return sets possible:
Nothing (as you say) -> Something missing/wrong in the code (compare yours with mine)
Empty array: Your query didn't find anything, adapt the search value(s)
One or more entries in the array -> All fine, what you were looking for!
Hope that helps!
When querying by _id there is a built in method: http://devcenter.kinvey.com/angular/guides/datastore#FetchingbyId
Try switching to var stream = dataStore.findById('entity-id');
Also check to make sure you don't have any preFetch or postFetch BL that is interfering with the query.
I have created following function in AngularJS
var enq_dt = new Date();
$.post("/api/EMSAPI/EnquiryDetails?enq_no="+o_enq_no, null, function (returnedData) {
enq_dt = returnedData["D_O_O"];
console.log("Loading Post Block");
console.log(enq_dt);
});
console.log("Loading General Block ");
console.log(enq_dt);
$scope.CurrentQuotation = {
EnquiryNo:o_enq_no,
EnquiryDate: enq_dt,
QuotationBy:"TEST"
};
I am getting following result in console window.
Loading General Block
2010-11-26T00:00:00
Loading Post Block
2010-12-12T00:00:00
I want to Load Post block first and after that I want to run General Block.
What I am missing (I am new to Angular) ?
Thanks in advance.
I suggest you Google the word "asynchronous". In JavaScript, things like HTTP requests are almost always asynchronous.
To get your general code to run after the post, call it with .then():
function generalCode() {
console.log("Loading General Block ");
console.log(enq_dt);
$scope.CurrentQuotation = {
EnquiryNo:o_enq_no,
EnquiryDate: enq_dt,
QuotationBy:"TEST"
};
}
var enq_dt = new Date();
$.post("/api/EMSAPI/EnquiryDetails?enq_no="+o_enq_no, null)
.then(function (returnedData) {
enq_dt = returnedData["D_O_O"];
console.log("Loading Post Block");
console.log(enq_dt);
})
.then(generalCode);
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.
In my angular app I want to make changes to several locations in my firebase with a mix of transactions and set. I have written a promise chain with a little help. Now I need to handle any errors that may occur.
In the event of an error on any of the promises I would want to roll back any changes made in firebase (the successful promises) and alert the user to the failure.
Current code below
$scope.addNewPost = function() {
var refPosts = new Firebase(FBURL).child('/posts').push();
// Get tags into array for incrementing counters
var tags = $scope.post.tags.split(', ');
var allPromises = [];
// Iterate through tags and set promises for transactions to increment tag count
angular.forEach(tags, function(value, index){
var dfd = $q.defer();
var refTag = new Firebase(FBURL).child('/tags/' + value);
refTag.transaction( function (current_value) {
return current_value + 1;
}, function(error, committed, snapshot) {
if (committed) {
dfd.resolve( snapshot );
} else {
dfd.reject( error );
}
});
allPromises.push( dfd.promise );
});
// Add promise for setting the post data
var dfd = $q.defer();
refPosts.set( $scope.post, function (error) {
if (error) {
dfd.reject(error);
} else {
dfd.resolve('post recorded');
}
});
allPromises.push( dfd.promise );
$q.all( allPromises ).then(
function () {
$scope.reset(); // or redirect to post
},
function (error) {
// error handling goes here how would I
// roll back any data written to firebase
alert('Error: something went wrong your post has not been created.');
}
);
};
So what I need to know is how do I roll back any changes that happen to my firebase data in the event that one of these promises fail. There could be any number of updates happening in firebase. (for example: 3 tags being incremented via transaction and the post data being set)
How would I write the failure function to calculate what was successful and undo it? If this is this even possible.
--------------- sub question from original post has been solved ---------------
Also how do you force errors? I've tried setting a variable like below but it doesn't seem to work, is there something wrong with my .then?
refPosts.set( $scope.post, function (error) {
var forceError = true;
if (forceError) {
dfd.reject(forceError);
} else {
dfd.resolve('post recorded');
}
allPromises.push( dfd.promise );
});
There are two instances of this line, and they are both in the wrong place:
allPromises.push( dfd.promise );
In the first block, it should be in the last statement in the forEach callback, not in the transaction callback.
In the second block, it should be after the call to set(), not in the callback.
The way your code is written now, $q.all() is getting an empty array of promises. That could also be what's interfering with the forceError test you're attempting.
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