Objective
I am trying to use the google script editor to import csv files on google drive into my google sheet. Can someone clarify to me what I'm misunderstanding about the script and what I need to tweak to allow me to paste multiple sheet requests into the below? Apologies if this is something straight forward, this is my first time using the script editor, and I'm not familiar with a lot of this.
Issue
At current my code only populates 1 sheets worth of data. as opposed to treating the second part as the next sheet that I want populated, with a different csv sheet ID.
What I've tried
Changing the variables to be more unique to get the sheet to treat my variables as different, as I thought it was wiping each time.
Reviewing other online help forums without luck of finding something
similar that I can understand.
Current Code
function onOpen(e) {
SpreadsheetApp.getUi()
.createMenu('RefreshData')
.addItem('Run getCSV', 'getCSV')
.addToUi()
}
function getCSV() {
//ENTER YOUR CSV FILE ID IN THE getFileByID in the ""
var file = DriveApp.getFileById("<file_id>");
var csvFile = file.getBlob().getDataAsString();
var csvData = Utilities.parseCsv(csvFile);
//CHANGE SHEET NAME TO WHATEVER YOUR SHEET IS CALLED
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
sheet.clear();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
function getCSV() {
//ENTER YOUR CSV FILE ID IN THE getFileByID in the ""
var file = DriveApp.getFileById("<file_id2>");
var csvFile = file.getBlob().getDataAsString();
var csvData = Utilities.parseCsv(csvFile);
//CHANGE SHEET NAME TO WHATEVER YOUR SHEET IS CALLED
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
sheet.clear();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
You have getCSV() defined twice and that will cause problems. Function names, like variables, should be unique. Otherwise, they'll get rewritten.
Take the case of two test() functions. Every time you run testAll(), the output will always be 2.
function testAll() {
test(); // 2.0
test(); // 2.0
}
function test() {
Logger.log(1);
}
function test() {
Logger.log(2);
}
What you could do is modify getCSV() so that it accepts inputs and then create a new function that will pass the data into it. Then call that new function in your menu.
/**
* Add a custom menu to the spreadsheet.
*/
function onOpen(e) {
SpreadsheetApp.getUi()
.createMenu("RefreshData")
.addItem("Get CSVs", "importSheets")
.addToUi();
}
/**
* Imports all CSV files.
*/
function getCSVs() {
// Define the CSV files and where you want them to be saved
var csvs = [
{ fileId: "FILE_ID_1", sheetName: "Sheet1" },
{ fileId: "FILE_ID_2", sheetName: "Sheet2" }
];
// Import the CSVs
for (var i = 0; i < csvs.length; i++) {
getCSV_(csvs[i].fileId, csvs[i].sheetName);
}
}
/**
* Get the CSV data from a specified file and import into the desired
* sheet of the active spreadsheet.
* #param {String} fileId - The file ID of the CSV file
* #param {String} sheetName - The name of the destination sheet
*/
function getCSV_(fileId, sheetName) {
//ENTER YOUR CSV FILE ID IN THE getFileByID
var file = DriveApp.getFileById(fileId);
var csvFile = file.getBlob().getDataAsString();
var csvData = Utilities.parseCsv(csvFile);
//CHANGE SHEET NAME TO WHATEVER YOUR SHEET IS CALLED
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
sheet.clear().getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
Created an additional function getCSV2 which states the sheet name and ID which is then populated and looped in the getCSV function.
function onOpen(e) {
SpreadsheetApp.getUi()
.createMenu('RefreshData')
.addItem('Run getCSV', 'getCSV')
.addToUi()
}
function getCSV() {
getCSV2("sheet1", "<file_id1>");
getCSV2("sheet2", "<file_id2>");
}
function getCSV2(name, id) {
var file = DriveApp.getFileById(id);
var csvFile = file.getBlob().getDataAsString();
var csvData = Utilities.parseCsv(csvFile);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(name);
sheet.clear();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
Related
I have a folder called "Adform" in my Drive and I want to take all the spreadsheets from there and modify them by adding new columns, change headers.
At this point I managed to get the files name, one by one, but I don't know how to use SpreadSheetApp to modify those Spreadsheets.
var folders = DriveApp.getFoldersByName('Adform');
while (folders.hasNext()) {
var files = folders.next().getFiles();
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getName());
}
}
How to loop through all the Spreadsheets in a Drive folder
You are almost there. The best way in my opinion is to check if the mime type of the file is application/vnd.google-apps.spreadsheet, and if so, get the id. Then pass this id to another function that will modify the Spreadsheet in any way that you want.
function myFunction() {
var folders = DriveApp.getFoldersByName('Adform');
while (folders.hasNext()) {
var files = folders.next().getFiles();
while (files.hasNext()) {
var file = files.next();
// Check if file is a spreadsheet
if (file.getMimeType() === "application/vnd.google-apps.spreadsheet") {
// Call the function to modify the spreadsheet with the file id
modifySpreadhsheet(file.getId())
}
}
}
}
function modifySpreadsheet(id) {
// Open the file with the id
var file = SpreadsheetApp.openById(id);
// Get all the sheets
var sheets = file.getSheets()
// Get the first sheet
var firstSheet = sheets[0]
// Get the range that contains all the data in that sheet
var range = firstSheet.getDataRange();
// Get all the values in that range
var values = range.getValues();
Logger.log(values)
}
This sample function will just get the first sheet of the spreadsheet and then Log all the data within that spreadsheet to the logger.
Then you can use functions like setValues(values) to modify the content as needed.
References
getMimeType()
getId()
openById(id)
getSheets()
getDataRange()
getValues()
I have a script in my G Sheets that imports a CSV from Google Drive and I have attached it to a clickable button within the workbook. It works great. Here is the script:
function myFunction() {
var file = DriveApp.getFilesByName("FileName.csv").next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Imported File");
sheet.getRange('A1:K10000').clearContent();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
However, I would like to automate the process further by having it run this function when a specific cell is edited. I will run a webhook to automate changing this cell.
So, as a trial run I found a very helpful stackoverflow question here and created this code to simply clear the cells:
function onEdit(e) {
if (e.range.getSheet().getName() === 'Imported File') {
if (e.range.getA1Notation() === 'L2') {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Imported File");
sheet.getRange('A1:K10000').clearContent();
}
}
}
Again, this works great. So my issue is that whenever I put the full original code inside the edit function it does not work. Have I missed something?
function onEdit(e) {
if (e.range.getSheet().getName() === 'Imported File') {
if (e.range.getA1Notation() === 'L2') {
var file = DriveApp.getFilesByName("FileName.csv").next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Imported File");
sheet.getRange('A1:K10000').clearContent();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
}
}
Simple triggers such as onEdit() have ScriptApp.AuthMode.LIMITED permissions, so they do not have access to services such as Drive.
From the documentation:
LIMITED A mode that allows access to a limited subset of services. This mode occurs when an add-on or a script bound to a document
executes an onOpen(e) or onEdit(e) simple trigger, except in the case
described for NONE.
Solution:
You can create an installable trigger on the fly, e.g. when the webhook is run like this:
function createTrigger() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ScriptApp.newTrigger('csvEdit').forSpreadsheet(ss).onEdit().create();
}
Run the function manually first to establish the necessary DriveApp permissions. Then the new trigger will work as usual, when L2 cell is edited.
function csvEdit(e) {
if (e.range.getSheet().getName() === 'Imported File') {
if (e.range.getA1Notation() === 'L2') {
var file = DriveApp.getFilesByName("FileName.csv").next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Imported File");
sheet.getRange('A1:K10000').clearContent();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
}
}
I have a script which I have created in Google drive as I want it to be a standalone script to that of the spreadsheet - mainly because other users have been fidling with the scripts and the sheet didn't function properly until i found all the problems!!
One of the scripts is this:
var SORT_COLUMN_INDEX = 2;
var ASCENDING = true;
var NUMBER_OF_HEADER_ROWS = 2;
var activeSheet;
function autoSort(sheet) {
var range = sheet.getDataRange();
if (NUMBER_OF_HEADER_ROWS > 0) {
range = range.offset(NUMBER_OF_HEADER_ROWS, 0);
}
range.sort( {
column: SORT_COLUMN_INDEX,
ascending: ASCENDING
} );
}
function onClickButton() {
var sheet = SpreadsheetApp.getActiveSheet();
autoSort(sheet);
}
I have found this online which apparently links the app script to the spreadsheet but this doesn't work for me... var ss = SpreadsheetApp.OpenFileById(xxx__xxx)
(xxx__xxx) being the spreadsheet id taken as: https://docs.google.com/spreadsheets/d/xxx__xxx/edit#gid=1611726502
This just returns the following when I run the script:
TypeError: Cannot find function OpenFileById in object.
Please could someone assist on where i either put the code var ss = SpreadsheetApp.OpenFileById(xxx__xxx) within the script or the best script to use find the spreadsheet based on the sheet ID?
p.s. i will need to run the function onClickButton if that makes any difference...
Sorting a Spreadsheet from a Standalone Script
var ssid="Spreadsheet Id";
function sortingSS() {
var ss=SpreadsheetApp.openById(ssid);
var sh=ss.getSheetByName('Sheet3');
var rg=sh.getRange(2,1,sh.getLastRow()-1,sh.getLastColumn());
rg.sort({column:1,ascending:true});
}
Sheet before sort
Sheet after sort
Adding it to a menu
function onOpen() {
SpreadsheetApp.getUi().createMenu("Project Menu")
.addItem("Sorting Spreadsheet", "sortingSS")
.addToUi();
}
Creating a button of your own
I want to have my app script generate output to a SPECIFIC sheet, not the first sheet in the document.
i am looking to do the following:
Have 2 app scripts run on timers for a single google sheet document
App Script 1 will put data into sheet1, named "order_1"
App script 2 will put data into sheet2, named "orders_2"
my code currently puts the output into the active sheet, which is always the first sheet in the document
function import_Completed_orders_FromGmail() {
var threads = GmailApp.search('subject: "orders"');
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
// Is the attachment a CSV file
attachment.setContentTypeFromExtension();
if (attachment.getContentType() === "text/csv") {
var sheet = SpreadsheetApp.getActiveSheet();
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
// Remember to clear the content of the sheet before importing new data
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length,
csvData[0].length).setValues(csvData);
}
}
is there a way to define "ActiveSheet" by name? or to specify a specific sheet to put this output?
Use getSheetByName(name) method from Class Spreadsheet.
In order to get a Spreadsheet object you will have to use one of the SpreadsheetApp methods to open a spreadsheet like openById(id), open(file), openByUrl(url), getActiveSpreadheet().
You can get both sheet separately and use them in the code.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("order_1");
var sheet2 = ss.getSheetByName("order_2");
I'm trying to fill cells with hyperlinks to ranges in Google Sheets app script with the same desired outcome I would get had I done it in GUI. I managed to create hyperlinks to sheet in the form of "gid=..." with the ... being a sheetID. But I struggle to get the rangeID that is used when generating the hyperlink in GUI e.g.
HYPERLINK("#rangeid=1420762593";"'List 4'!F2:F15")
Is it possible to create hyperlinks to ranges in app script?
Yes, you can do this in App Script. Here's a very simple implementation where the HYPERLINK function is built and appended to a cell:
function hyperlinkRange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Sheet1");
var sheet2 = ss.getSheetByName("Sheet2").getSheetId();
sheet1.getRange("A1").setValue('=hyperlink("#gid='+sheet2+'&range='+sheet1.getRange('A1:A10').getA1Notation()+'", "Click to jump to Sheet 2")');
}
You can combine this with loops to set a value of links across multiple sheets.
Custom functions
Use in a formula.
Simple range:
=HYPERLINK(getLinkByRange("Sheet1","A1"), "Link to A1")
Named range:
=HYPERLINK(getLinkByNamedRange("NamedRange"), "Link to named range")
The code, insert into the script editor (Tools > Script Editor):
function getLinkByRange(sheetName, rangeA1, fileId)
{
// file + sheet
var file = getDafaultFile_(fileId);
var sheet = file.getSheetByName(sheetName);
return getCombinedLink_(rangeA1, sheet.getSheetId(), fileId, file)
}
function getLinkByNamedRange(name, fileId)
{
// file + range + sheet
var file = getDafaultFile_(fileId);
var range = file.getRangeByName(name);
var sheet = range.getSheet();
return getCombinedLink_(range.getA1Notation(), sheet.getSheetId(), fileId, file)
}
function getDafaultFile_(fileId)
{
// get file
var file;
if (fileId) { file = SpreadsheetApp.openById(fileId); }
else file = SpreadsheetApp.getActive();
return file;
}
function getCombinedLink_(rangeA1, sheetId, fileId, file)
{
var externalPart = '';
if (fileId) { externalPart = file.getUrl(); }
return externalPart + '#gid=' + sheetId + 'range=' + rangeA1;
}
Here is another example. Hopefully, it is clean and self-explanatory
function hyperlinkRange(shDest,rgDest,shSrc,rgSrc,linkText) {
// get the spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet()
// get the destination sheet id
var idDest = shDest.getSheetId()
// link the range
var formula = '=hyperlink("#gid='+idDest+'&range='+rgDest+'","'+linkText+'")'
shSrc.getRange(rgSrc).setValue(formula)
}
In case you want to create a link to another sheet which will open the sheet in the same browser tab here is what you want to do:
1. Get the id of the sheet. Check the link in your browser and you will see #gid=x where x is the sheet id
2. Then you want to set the formula (hyperlink) to the cell and make it show as a hyperlink
SpreadsheetApp.getActiveSheet().getRange("A1").setFormula('=HYPERLINK("#gid=X","test")').setShowHyperlink(true);
If you don't use setShowHyperlink(true) it will be shown as a regular text.