Cannot download firebase storage files with js loop - javascript

I am trying to get the download url of some files of firebase storage with a javascript loop like shown in the code below. It creates the elements correctly but it only assigns a "src" to the second one (in the case of working with 2 files).
var photosContainer = document.getElementById('photosContainer');
var photoNumber = firebase.database().ref('main/' + keyParent).child(key + '/number_photos');
photoNumber.on('value', function(snapshot){
for(var i = 0; i < snapshot.val(); i++){
var divPhoto = document.createElement('div');
photosContainer.appendChild(divPhoto);
var photo = document.createElement('img');
photo.style.width = '100%';
divPhoto.appendChild(photo);
var photosStorage = firebase.storage().ref('main/');
photosStorage.child(i + key).getDownloadURL().then(function(url) {
photo.src = url;
}).catch(function(error) {
// Handle any errors
console.log('An error occurred.')
});
}
})

when getDownloadURL() got its file path from Firebase, the "photo.src = url;" is the second element Object.

it works by creating an array, adding the urls to the array and then erasing the previous elements and creating the new ones inside array.forEach().

Related

GAS how upload multiple file in google drive

I'm trying to upload multiple files into Google Drive Using Google Apps Script.
My code work fine when I want to upload one file
// UPLOAD IMG IN GOOGLE DRIVE
var url = 'http://www.pngall.com/wp-content/uploads/2/1-Number-PNG-Picture.png';
var response = UrlFetchApp.fetch(url); // get api endpoint
var rc = response.getResponseCode();
if(rc=200){
var fileBlob = response.getBlob();
var folder = DriveApp.getFolderById("xxxxxx")
if(folder !=null) {
var file_img = folder.createFile(fileBlob)
var img = file_img.getUrl();
}
}
} else {
var img = "";
}
// APPEND VALUE TO SHEET
sheet.appendRow([img]);
I'm trying to modify the above script in order to upload multiple files into google drive, but my code doesn't works.
This is my (not working) code:
// UPLOAD IMG IN GOOGLE DRIVE
var url = ['http://www.pngall.com/wp-content/uploads/2/1-Number-PNG-Picture.png', 'https://www.yourcloudworks.com/wp-content/uploads/2019/09/number-digit-2-png-transparent-images-transparent-backgrounds-Number-2-PNG-images-free-download_PNG14949.png'];
for(var i=0; i<url.length; i++){
var response = UrlFetchApp.fetchAll(url);
var rc = response.getResponseCode();
if(rc=200){
var fileBlob = response.getBlob();
var folder = DriveApp.getFolderById("xxxxxx")
if(folder !=null) {
var file_img = folder.createFile(fileBlob[i])
var img = file_img.getUrl()[i];
}
}
} else {
var img = "";
}
// APPEND VALUE TO SHEET
sheet.appendRow(img[i]);
}
TypeError: response.getResponseCode is not a function
Any help?
Modification points:
In your script, for(var i=0; i<url.length; i++){}else{} is used. I thought that you might misunderstand the if statement and for loop.
When you want to compare the value at the if statement, please modify if(rc=200){ to if(rc==200){.
The response value from UrlFetchApp.fetchAll(url) is an array.
I think that the reason of the error message is this.
folder.createFile(fileBlob[i]) is folder.createFile(fileBlob).
file_img.getUrl()[i] is file_img.getUrl().
When file_img.setTrashed(true) is used, the downloaded files are moved to the trashbox. If you don't want to move them to the trashbox, please remove the line.
I think that when the values are put to the Spreadsheet by one request, the process cost will be low. In your script, I would like to propose to use setValues instead of appendRow.
When above points are reflected to your script, it becomes as follows.
Modified script:
Please copy and paste the following modified script. And please set the variable of sheet, and the folder ID.
function myFunction() {
// var sheet = SpreadsheetApp.getActiveSheet();
var url = ['http://www.pngall.com/wp-content/uploads/2/1-Number-PNG-Picture.png', 'https://www.yourcloudworks.com/wp-content/uploads/2019/09/number-digit-2-png-transparent-images-transparent-backgrounds-Number-2-PNG-images-free-download_PNG14949.png'];
var requests = url.map(u => ({url: u, muteHttpExceptions: true}));
var response = UrlFetchApp.fetchAll(requests);
var imgs = [];
for (var i = 0; i < response.length; i++) {
if (response[i].getResponseCode() == 200) {
var fileBlob = response[i].getBlob();
var folder = DriveApp.getFolderById("xxxxxx");
if (folder != null) {
var file_img = folder.createFile(fileBlob);
imgs.push([file_img.getUrl()]);
// file_img.setTrashed(true); // When this script is used, the downloaded files are moved to the trashbox.
}
}
}
if (imgs.length > 0) {
sheet.getRange(sheet.getLastRow() + 1, 1, imgs.length).setValues(imgs);
}
}
When muteHttpExceptions: true is used, the script can be run even when an error occurs.
References:
fetchAll(requests)
if...else
Loops and iteration

Trying to get folder path of file in Google Apps Script

I am trying to create a function in Google Apps Script that finds the file path of the folder.
Here is the error: TypeError: Cannot read property 'appendParagraph' of null (line 20, file "Code")
function getRoot() {
var doc = DocumentApp.getActiveDocument();
var header = DocumentApp.getActiveDocument().getHeader();
var name = doc.getName();
var id = doc.getId();
var txt = "Master Folder";
var parents = [];
var folders = DriveApp.getFileById(id).getParents();
while (folders.hasNext()){
var parent = folders.next();
var n = parent.getName();
parents.push(n);
}
var pLen = parents.length;
for (i = 0; i < pLen; i++){
txt = txt + "//" + parents[i];
}
var headerPar = header.appendParagraph(txt);
}
I believe your goal as follows.
You want to know the reason of the error message of TypeError: Cannot read property 'appendParagraph' of null.
You want to remove the error.
You want to retrieve the folder path of the active Google Document.
For this, how about this answer?
Modification points:
In your script, I think that the reason of your error message is the header is not existing in the Google Document. By this, header retrieved by getHeader() is null, and then, the error occurs. So in this case, please add the header using addHeader().
doc of var doc = DocumentApp.getActiveDocument(); can be used for getHeader().
If you want to retrieve the folder path from the root folder, I think that your script is required to be modified. In your current script, when the Google Document is put in the nested folders, only parent of the Document is retrieved.
When your script is modified using above points, it becomes as follows.
Modified script:
function getRoot() {
var doc = DocumentApp.getActiveDocument();
var header = doc.getHeader() || doc.addHeader(); // Modified
var name = doc.getName();
var id = doc.getId();
var txt = "Master Folder";
var parents = [];
var folders = DriveApp.getFileById(id).getParents();
// --- I modified below script
while (folders.hasNext()) {
var folder = folders.next();
parents.push(folder.getName());
folders = folder.getParents();
}
parents = parents.reverse();
// ---
var pLen = parents.length;
for (i = 0; i < pLen; i++){
txt = txt + "//" + parents[i];
}
var headerPar = header.appendParagraph(txt);
}
By this modification, when the header is existing, doc.getHeader() is used. When the header is not existing, doc.addHeader() is used. And, when the active Document is put to the folder path like root -> folder1 -> folder2, Master Folder//MyDrive//folder1//folder2 is put to the header.
References:
getHeader()
addHeader()

Exporting table data from HTML page to CSV file using the Browser Console (Chrome)

I need to extract some data from a web page and store it in a CSV file to be opened in Excel. I am trying to do this from the browser console, but I am getting a non-defined error.
So far I've tried using this code to export the table:
function exportTableToCSV(filename) {
var csv = [];
var rows = document.querySelectorAll("table tr");
for (var i = 0; i < rows.length; i++) {
var row = [], cols = rows[i].querySelectorAll("td, th");
for (var j = 0; j < cols.length; j++)
row.push(cols[j].innerText);
csv.push(row.join(","));
}
// Download CSV file
downloadCSV(csv.join("\n"), filename);
}
When I define this function and run it, I get a "downloadCSV not defined error". Are there any limitations to the built in Browser console in Chrome, besides the obvious ones?
This code also needs to be run in a loop, since there are multiple pages with tables, but it would be nice to have it all located in a single CSV file. For starters it should really just extract anything it can find in the table. I'll dive in and extract the specific fields I need later when I get this working.
Edit:
function downloadCSV(csv, filename) {
var csvFile;
var downloadLink;
csvFile = new Blob([csv], {
type: "text/csv"
});
downloadLink = document.createElement("a");
downloadLink.download = filename;
downloadLink.href = window.URL.createObjectURL(csvFile);
downloadLink.style.display = "none";
document.body.appendChild(downloadLink);
downloadLink.click();
}
What you could do is, instead of creating a csv for every table, to save all the data from the pages to some storage, like for example the local storage:
$(document).ready(function() {
$(window).unload(saveSettings);
loadlist();
});
function loadlist() {
savedlist = localStorage.list;
}
function savelist() {
localStorage.list = savedlist + currentlist;
}
Instead of immediately downloading the csv, collect all your data in the storage using the examples above (you will need to adjust them to your needs). Then, once you have all data, put it into a single csv and then download this. Afterwards, delete the data from the storage:
function deletelist() {
localStorage.removeItem(list);
}
The local storage persists across your pages from the same domain, until cleared by you or when the user deletes his browser data manually.

Google Drive + Script throws permissions error even through I'm owner and granted permission

I'm trying to create a basic script on a 12-hour timer trigger that loops through each of my Google Calendars by their ICAL URL, and downloads the ICAL for a folder on my Google Drive (for backup purposes). It throws this error
"No item with the given ID could be found, or you do not have permission to access it. (line 23, file "Code")" (Line #23 is var folder... )
Running the script does download and save the ICAL file on the first run through the loop (and if I manually pass in each unique ICAL URL one at a time), but the error then terminates the loop. Seeing as how I've authorized access already and am the owner of everything here, I'm not sure what else I need.
var calendarsToSave = [
"https://calendar.google.com/calendar/ical/inXXXXXXX.com/privateXXXX/basic.ics",
"https://calendar.google.com/calendar/ical/XXXXX.com_XXXXXXup.calendar.google.com/private-XXXXXXX/basic.ics"
];
var folder = '123xxxxxxxxv789'; // my gdrive folder
function downloadFile(calendarURL,folder) {
var fileName = "";
var fileSize = 0;
for (var i = 0; i < calendarsToSave.length; i++) {
var calendarURL = calendarsToSave[i];
var response = UrlFetchApp.fetch(calendarURL, {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob()
var folder = DriveApp.getFolderById(folder); // << returns a permissions error thus terminating the for loop
var file = folder.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
var fileInfo = { "rc":rc, "fileName":fileName, "fileSize":fileSize };
return fileInfo;
} // end for loop
}
Updated: You are also re-initializing a variable that already exists from the parameters and as a global variable so we can remove the parameter if you want to keep the global variable.
We can also move the place where you get the Google Folder object. It stays the same every time so we don't need to retrieve it again.
var calendarsToSave = [
"https://calendar.google.com/calendar/ical/inXXXXXXX.com/privateXXXX/basic.ics",
"https://calendar.google.com/calendar/ical/XXXXX.com_XXXXXXup.calendar.google.com/private-XXXXXXX/basic.ics"
];
var folder = '123xxxxxxxxv789'; // my gdrive folder
function downloadFile(calendarURL) {
var fileName = "";
var fileSize = 0;
var gfolder = DriveApp.getFolderById(folder);
for (var i = 0; i < calendarsToSave.length; i++) {
var calendarURL = calendarsToSave[i];
var response = UrlFetchApp.fetch(calendarURL, {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob()
var file = gfolder.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
var fileInfo = { "rc":rc, "fileName":fileName, "fileSize":fileSize };
return fileInfo;
} // end for loop
}
Let see where that gets us.
Your "folder" variable is outside the function, causing the data to be inaccessible to the "downloadFile" function.
Google apps coding seems to require variables to be in a function to be defined. I would recommend moving both "calendarsToSave" and "folder" to the inside of "downloadFile"
Here is an example that will return your error:
var folder = '1HSFBPfPIsXWvFEb_AalFYalkPwrOAyxD';
function myFunction() {
var folder = DriveApp.getFolderById(folder);
var name = folder.getName();
Logger.log(name);
}
And here is one that will return the file name:
function myFunction() {
var folder = '1HSFBPfPIsXWvFEb_AalFYalkPwrOAyxD';
var folder = DriveApp.getFolderById(folder);
var name = folder.getName();
Logger.log(name);
}

Get String Value of Blob Passed to e.parameter in Apps Script

I'm using this code to get a blob passed to a function:
function submit(e){
var arrayBlob = e.parameter.arrayBlob;
Logger.log("arrayBlob #2 = " + arrayBlob.getDataAsString());
This is the error I get:
Execution failed: TypeError: Can not find getDataAsString function in
the Blob object.'arrayBlob'
How do I get the string value of this blob?
Here is my code:
function showList(folderID) {
var folder = DocsList.getFolderById(folderID);
var files = folder.getFiles();
var arrayList = [];
for (var file in files) {
file = files[file];
var thesesName = file.getName();
var thesesId = file.getId();
var thesesDoc = DocumentApp.openById(thesesId);
for (var child = 0; child < thesesDoc.getNumChildren(); child++){
var thesesFirstParagraph = thesesDoc.getChild(child);
var thesesType = thesesFirstParagraph.getText();
if (thesesType != ''){
var newArray = [thesesName, thesesType, thesesId];
arrayList.push(newArray);
break;
}
}
}
arrayList.sort();
var result = userProperties.getProperty('savedArray');
arrayList = JSON.stringify(arrayList);
var arrayBlob = Utilities.newBlob(arrayList);
Logger.log("arrayBlob #1 = " + arrayBlob.getDataAsString()); // Here it`s OK
var mydoc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setWidth(550).setHeight(450);
var panel = app.createVerticalPanel()
.setId('panel');
panel.add(app.createHidden('arrayBlob', arrayBlob));
var label = app.createLabel("Selecione os itens desejados").setStyleAttribute("fontSize", 18);
app.add(label);
arrayList = JSON.parse(arrayList);
panel.add(app.createHidden('checkbox_total', arrayList.length));
for(var i = 0; i < arrayList.length; i++){
var checkbox = app.createCheckBox().setName('checkbox_isChecked_'+i).setText(arrayList[i][0]);
Logger.log("arrayList[i][0] = " + arrayList[i][0]);
Logger.log("arrayList[i] ====> " + arrayList[i]);
panel.add(checkbox);
}
var handler = app.createServerHandler('submit').addCallbackElement(panel);
panel.add(app.createButton('Submit', handler));
var scroll = app.createScrollPanel().setPixelSize(500, 400);
scroll.add(panel);
app.add(scroll);
mydoc.show(app);
}
function submit(e){
var arrayBlob = e.parameter.arrayBlob;
Logger.log("arrayBlob #2 = " + arrayBlob.getDataAsString());
// Continues...
}
I'd like the solution worked with more than one user simultaneous using the script.
Update:
Add a global variable OUTSIDE of any function:
var arrayBlob = Utilities.newBlob("dummy data");
function showList(folderID) {
Code here ....
};
Check that the code has access to the blob:
function submit(e){
Logger.log("arrayBlob.getDataAsString(): " + arrayBlob.getDataAsString());
//More Code . . .
}
This solution eliminates the need of embedding a hidden element in the dialog box with a value of the blob.
You won't need this line:
panel.add(app.createHidden('arrayBlob', arrayBlob));
There are other changes I'd make to the code, but I simply want to show the main issue.
Old Info:
In the function showList(), the method getDataAsString() works on the blob named arrayBlob.
Logger.log("arrayBlob #1 = " + arrayBlob.getDataAsString()); // Here it`s OK
In the function, submit(), the same method does not work.
var arrayBlob = e.parameter.arrayBlob;
In the function showList(), the code is assigning a newBlob to the variable arrayBlob. So arrayBlob is available to have the getDataAsString() method used on it.
var arrayBlob = Utilities.newBlob(arrayList);
In the function, submit(), you are trying to pass the arrayBlob blob variable into the submit() function, and reference it with e.parameter.
If you put a Logger.log() statement in the submit() function.
function submit(e){
Logger.log('e: ' + e);
Logger.log('e.parameter` + e.parameter);
var arrayBlob = e.parameter.arrayBlob;
Those Logger.log statements should show something in them. If there is nothing in e.parameter, then there is nothing for the .getDataAsString() to work on.
It looks like you are putting the arrayBlob into a hidden panel.
panel.add(app.createHidden('arrayBlob', arrayBlob));
But when the object is getting passed to the submit(e) function, the arrayBlob might not be getting put into that object.
So, what I'm saying is, the:
Logger.log("arrayBlob #2 = " + arrayBlob.getDataAsString());
Line may be perfectly good, but there is no arrayBlob there to work on. This hasn't fixed your problem, but do you think I'm understanding part of what is going on?
I'm not sure why you are using Blob's here at all, you could simply work with JSON instead.
However, if you have a reason to use Blobs, you can pass the JSON data through your form and create the Blob in your handler, as the modified code below does:
function showList(folderID) {
var folder = DocsList.getFolderById(folderID);
var files = folder.getFiles();
var arrayList = [];
for (var file in files) {
file = files[file];
var thesesName = file.getName();
var thesesId = file.getId();
var thesesDoc = DocumentApp.openById(thesesId);
for (var child = 0; child < thesesDoc.getNumChildren(); child++){
var thesesFirstParagraph = thesesDoc.getChild(child);
var thesesType = thesesFirstParagraph.getText();
if (thesesType != ''){
var newArray = [thesesName, thesesType, thesesId];
arrayList.push(newArray);
break;
}
}
}
arrayList.sort();
var result = UserProperties.getProperty('savedArray');
//get JSON data pass through form.
var arrayBlob = JSON.stringify(arrayList);
var mydoc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setWidth(550).setHeight(450);
var panel = app.createVerticalPanel()
.setId('panel');
//include JSON Data in the form.
panel.add(app.createHidden('arrayBlob', arrayBlob));
var label = app.createLabel("Selecione os itens desejados").setStyleAttribute("fontSize", 18);
app.add(label);
panel.add(app.createHidden('checkbox_total', arrayList.length));
for(var i = 0; i < arrayList.length; i++){
var checkbox = app.createCheckBox().setName('checkbox_isChecked_'+i).setText(arrayList[i][0]);
Logger.log("arrayList[i][0] = " + arrayList[i][0]);
Logger.log("arrayList[i] ====> " + arrayList[i]);
panel.add(checkbox);
}
var handler = app.createServerHandler('submit').addCallbackElement(panel);
panel.add(app.createButton('Submit', handler));
var scroll = app.createScrollPanel().setPixelSize(500, 400);
scroll.add(panel);
app.add(scroll);
mydoc.show(app);
}
function submit(e){
var arrayBlob = Utilities.newBlob(e.parameter.arrayBlob);
Logger.log("arrayBlob #2 = " + arrayBlob.getDataAsString());
// Continues...
}
In the method you were using originally, the Blob itself was never included in the form, you were simply passing the string "Blob" around.
This is because the function createHidden(name, value); expects two strings as parameters, so it calls ".toString()" on the arrayBlob object, which returns the string "Blob".

Categories

Resources