Can't delete multiple images inside React Firebase Promises - reactjs

I am basically trying to delete specific Firebase data in both my storage and my database according to values I have stored in an array. I have an array of objects that cointains a key (which is a child key used for both FirebaseStorage and FirebaseDatabase, a picture name and a file destination. To make sure that I don't just remove the reference to the picture, I also want to delete it in Firebase Storage. Therefore, I thought that the use of a for-loop would solve the problem. This is my code so far:
var key, count = 0;
for (key in delArray) {
if (delArray.hasOwnProperty(key)) {
count++;
}
}
for (index = 0; index < count && canProceed; index++) {
canProceed = false;
var deletionFileLocation = storageNews.child(newsId + "/" + delArray[index].key + "/" + delArray[index].name);
deletionFileLocation.delete().then(() => {
databaseNews.child(newsId).child('thumbnails').child(delArray[index].key).remove().then(() => {
canProceed = true;
});
});
if (index == delArray.length) {
console.log('done');
}
}
The strange thing with this code, is that it removes all(I think, as far as I have noticed) pictures, but only reference in the database. In other words, it only removes one child in the DB. What am I doing wrong here? Do I need to use callbacks with async await? If so, how would I approach it? I am fairly new to React, and I can't seem to understand how I would do it.

It looks like you have it arranged so that the for loop hangs the process until any one of the remove() promises resolves. The missing concept is Promise.all().
// moved to a promise-returning function so we can see what's going on
function deleteDataAndStorage(newsId, obj) {
let path = newsId + "/" + obj.key + "/" + obj.name;
let deletionFileLocation = storageNews.child(path);
return deletionFileLocation.delete().then(() => {
return databaseNews.child(newsId).child('thumbnails').child(obj.key).remove();
});
}
Now the loop is simple and clear. Promise.all() does what the name says: it resolves with an array of results when all of the promises you pass it have resolved.
let promises = [];
for (index = 0; index < count; index++) {
promises.push(deleteDataAndStorage(newsId, delArray[index]));
}
return Promise.all(promises).then(result => {
console.log('done');
});

Related

Adding another check property to select default rows on antd table

Currently i have this code on my api call to add a check property (list) (based on api called data "resRole" and "res") which can be used inside of rowSelection to select all the default checked row.
However, now i have another table which I need to do the same thing. Just that instead of using resRole, now I will use resProject. Which i need to first add a key to, before i add a checkProject in "res".
As such, i updated the check to checkRole and intend to put in an additional checkDept (list) in the getAllUserRole's res.data.
Looking at my code, I do not know where I can implement it. It seems like I have to create it inside of the getDataUserRole() function but that seems too messy. And might cause some async issues.
Below is the code:
async function getDataProject() {
let resProject = await getAllProject();
if (resProject) {
setDataSourceProject(resProject.data);
}
}
async function getDataUserRole() {
let resRole = await getAllRoles();
if (resRole) {
//Add a key to every Role
for (var i = 0; i < resRole.data.length; i++) {
resRole.data[i]["key"] = i;
}
setDataSourceRole(resRole.data);
let res = await getAllUserRole();
if (res) {
console.log("getAllUserRole =", res);
for (var i = 0; i < res.data.length; i++) {
//add "check" to every email in the array
res.data[i]["checkRole"] = [];
//loop through all the roleIds array in each email
for (var j = 0; j < res.data[i].roleIds.length; j++) {
//if roleIds is not empty
if (res.data[i].roleIds.length != 0) {
//loop through all Role from getAllRoles and check if any roleIds match the Role. If match push the key of the Role into check
for (var k = 0; k < resRole.data.length; k++) {
if (res.data[i].roleIds[j] == resRole.data[k].id) {
res.data[i]["checkRole"].push(resRole.data[k].key);
}
}
}
}
}
//If groupChange (groupChange is state for storing value of radio button) is null, return untransformed data
if (!(groupChange)) {
setDataSourceUserRole(res.data);
}
//If groupChange has value, call the function with the state value as a parameter
else {
var treeData = groupData(res.data, groupChange)
setDataSourceUserRole(treeData);
}
}
}
}
Instead of Using it inside getDataUserRole(). Use it inside getAllUserRole(). and once you get your result just add additional data with the role and send it back to one function.
If you want to call it separately so then you to depend it one function on another because due to async it will not work properly

AWS GraphQL JSON string formatting

I'm attempting to create an object value to pass into DynamoDB using AWS AppSync and GraphQL. I'm very close to what I need but I'm stumbling on nested JSON.
Let's say I have an array:
let officers = [{"id":"0","IgRole":"Role1","IgName":"testname1","IgEmail":"testemail1","IgPhone":"testphone1","IgStart":"teststart1","IgEnd":"testend1"},
{"id":"1","IgRole":"Role2","IgName":"testname2","IgEmail":"testemail2","IgPhone":"testphone2","IgStart":"teststart2","IgEnd":"testend2"}]
I now want to create an object with each of the array values as a child object so, I do this:
for (let i in officers) {
officersJson['"' + officers[i].IgRole + '"'] = '{"Name":"' + officers[i].IgName + '","Email":"' + officers[i].IgEmail + '","Phone":"' + officers[i].IgPhone + '","Date commenced":"' + officers[i].IgStart + '","Date to end":"' + officers[i].IgEnd + '"}';
}
Here are the results:
Object {
"Role1": "{'Name':'testname1','Email':'testemail1','Phone':'testphone1','Date commenced':'teststart1','Date to end':'testend1'}",
"Role2": "{'Name':'testname2','Email':'testemail2','Phone':'testphone2','Date commenced':'teststart2','Date to end':'testend2'}"
}
I think the problem is that the each entire key / value is not in string format. If you look at
"Role1": "{......
you can see that the string breaks.
and this is the response from AWS:
Variable 'Officers' has an invalid value. Unable to parse {\"Role1\"={\"Nam
See the = sign
How can I format the object into a complete JSON string? I was fairly pleased I managed to get anywhere near the format I needed but this last bit has me stumped.
Finally worked it out. I needed a slightly different approach. Posting it in case it helps anyone else:
Firstly I created an array of roles, as this will be the keys for the value objects:
for (let i in officers) {
roles.push(officers[i].IgRole);
}
I then created a new array.
let arrOfficers = [];
for (let i in officers) {
arrOfficers.push(officers[i]);
}
I then use a function to create objects from an array:
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
let key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
let newresult = groupBy(arrOfficers, "IgRole");
Finally I create my object and then stringify it:
let officersJson = {};
for (let i in roles) {
officersJson[roles[i]] = newresult[roles[i]][0];
}
theObjectIwant = JSON.stringify(officersJson)

Return promise inside the for loop

I have a logic like below,
getSpecificCell: function(tableObject, rowText, columnCss) {
var ele = element.all(by.repeater(tableObject)).count().then(function(count) {
for (var i = 0; i < count; i++) {
return element(by.repeater(tableObject).row(i)).getText().then(function(txt) {
if (txt.indexOf(rowText) !== -1) {
return element(by.repeater(tableObject).row(i)).element(by.css('[' + columnCss + ']'));
}
});
}
});
return ele;
}
But it is returning the value in first iteration itself.
Is that possible to return the promise inside this kind of for loop or do we have any other solution for this?
First, you don't need to use for loops with an ElementArrayFinder. That's what the each() method is for.
Second, you shouldn't need to loop at all. It sounds like you should be using filter() to get the table cells that match your specification, though I'm not sure what exactly you're trying to accomplish.
var table = element.all(by.repeater(tableObject));
// list is an ElementArrayFinder of all elements that matched the filter
var list = table.filter(function (elem) {
return elem.getText().then(function (text) {
return txt.indexOf(rowText) !== -1
})
});
// do something with list
list.count().then(function (count) {
console.log(count);
});

Use an array of values for a slider

I want to use an array of id, for my little slider-viewer I'm building. I just want to display multiple things using 2 buttons next and previous.
For now I use something like this, using only 2 url id, but I need at least 20 urlid in my viewer :
var urlid1 = 'd3885ca76ac54e958c2855a4fbd3dbf3';
var urlid2 = '3aa64527d1614998b4812bfefbbc896a';
function Next() {
client.init( urlid2 );
}
function Previous() {
client.init( urlid1 ); }
So I've never use an array before, and the things I tried didn't work. Do you know a proper way to do that ?
This seems straight forward enough
var index = 0;
var array = ["url1", "url2", "url3", ...]
function next() {
index++;
if(index > array.length) {
index = 0;
}
client.init(array[index]);
}
function previous() {
index--;
if(index < 0) {
index = array.length;
}
client.init(array[index]);
}
It may be better practice to actually refactor those changes to the index variable to other functions to enable reuse, but this should give you an idea of how it is done.
If client is something that you have wrote then you might want to look at the naming of your functions, init is normally reserved for instantiating the class as new, from your example you seem to be changing a resource so you may want a function name like client.show(); or client.update();
Thank's Varedis.
Final code is :
var index = 0;
var array = ["0e4b4e0789bf41c7b05129a76de0abb0","3aa64527d1614998b4812bfefbbc896a","d3885ca76ac54e958c2855a4fbd3dbf3","8f927023e10c40b9b22d3c13df7c08aa"];
client.init(array[index]);
function next() {
index++;
if(index >= array.length) {
index = 0;
}
client.init(array[index]);
}
function previous() {
index--;
if(index < 0 ) {
index = array.length-1;
}
client.init(array[index]);
}
I had to use " index = array.length-1; " but I can't explain it. You know why ? How index could be 5 if I only have 4 values ?

synchronous for loop with promises

I have the following function that works but not as I want it to since each iteration needs the results of the iteration before.
There are plenty of similar questions but I'm finding it hard to reduce the solutions down to a pattern.
How can I rewrite the following function so that each loop iteration "waits" for the one before it?
$scope.updateBarcode = function() {
var itemcodes = $scope.itemcode.split(';');
// doc is JSPDF document, fetch will add a new page to the supplied doc.
var doc;
//fetch will unshift the returned doc onto the supplied array.
var result = [];
for (var i = 0; i < itemcodes.length; i++) {
var promise = $scope.fetch(doc, itemcodes[i],result);
promise.then(function(){
doc = result[0];
if (i >= itemcodes.length) {
doc.save(itemcodes[0] + '.pdf');
};
})
};
}
You need to assign the new promise from then() to your variable so that you build up a chain:
promise = promise.then(...);

Resources