I am trying to move my team's productivity to another sheet via Apps Script.
On the sheet "Prod" you can see the weekly productivity the team has put in. The "Approved" column has checkboxes where the work can be manually verified.
The second sheet is the "Archives" sheet. Where the Apps Script will move all of the responses from the "Prod" sheet over there.
Apps Script Code
function archive() {
// Get the information
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Prod');
var a = ss.getSheetByName('Archives');
var data = s.getRange('A2:F').getValues();
// Archive the results
for (i in data) {
var write = data[i];
a.appendRow(write);
}
// Clear the results
s.getRange('A2:E').clear();
s.getRange('F2:F').uncheck();
}
The Problem
The code works perfectly fine, however, when it is moving the "Prod" responses over to the "Archives" it includes the empty rows. This is because in the "Approved" column the checkbox is technically false, which means it's included. How would I go about changing the code to only transfer rows that have data in the A column?
Thanks!
I believe your goal as follows.
You want to copy the values from Prod to Archives when the value of column "A" in Prod is not empty.
Modification points:
In your script, all values of var data = s.getRange('A2:F').getValues(); is copied to Archives. So in this case, it is required to check the column "A" of data.
When appendRow() is used in a loop, the process cost will be high. Ref
When above points are reflected to your script, it becomes as follows.
Modified script:
function archive() {
// Get the information
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Prod');
var a = ss.getSheetByName('Archives');
var data = s.getRange('A2:F').getValues();
// Archive the results <--- I modified this part.
var copyValues = data.filter(([a]) => a.toString() != "");
a.getRange(a.getLastRow() + 1, 1, copyValues.length, copyValues[0].length).setValues(copyValues);
// Clear the results
s.getRange('A2:E').clear();
s.getRange('F2:F').uncheck();
}
References:
Benchmark: Reading and Writing Spreadsheet using Google Apps Script
filter()
setValues(values)
Related
I have a list of products with their attributes. Example column names are:
id, availability, condition, description, title, price, sale_price
In another sheet "cheat" I have a list of country codes like, FR and DE.
For each of those country codes I want to duplicate the product data and for each of those duplications add the country code in and "override" named column.
Here is a link to an example doc:
https://docs.google.com/spreadsheets/d/1kkcpovmWAcqa3hRBmsw-8g3R1FKIUfNqD5BF6tI4egI/edit?usp=sharing
Any help here is appreciated as I'm struggling to even get started.
I've checked your sample doc sheet and came up with this method below:
Recommendation
I have created a script with custom function named showResult():
function showResult() {
var ss = SpreadsheetApp.getActive();
var products = ss.getSheetByName('products'); //Gets all data on 'products' sheet
var cheat = ss.getSheetByName('cheat'); //Gets all data on 'cheat' sheet
var row = products.getDataRange().getNumRows(); //Counts current # of rows on 'products' sheet
var cheatRow = cheat.getDataRange().getNumRows(); //Counts current # of rows on 'cheat' sheet
var finalResult = [[products.getRange(1,1).getValue().toString(), //Initalize the column titles first on the finalResult array
products.getRange(1,2).getValue().toString(),
products.getRange(1,3).getValue().toString(),
products.getRange(1,4).getValue().toString(),
products.getRange(1,5).getValue().toString(),
'override']]; //Adds the 'override' column
for(var i=2; i<=cheatRow; i++){ //First loop to get each country codes
for(var x=2; x<=row; x++){ //Final loop to add each country codes to the each copy of grouped product values
finalResult.push([products.getRange(x,1).getValue().toString(),
products.getRange(x,2).getValue().toString(),
products.getRange(x,3).getValue().toString(),
products.getRange(x,4).getValue().toString(),
products.getRange(x,5).getValue().toString(),
cheat.getRange(i,1).getValue()
]);
}
}
SpreadsheetApp.getActive().getSheetByName('output').clear().getRange(1, 1, finalResult.length, finalResult[0].length).setValues(finalResult);
}
function onOpen() { //[Optional] Added a custom menu to manually to refresh your 'output' sheet
var ui = SpreadsheetApp.getUi();
ui.createMenu('Refresh output sheet')
.addItem('Refresh', 'showResult')
.addToUi();
}
This script will get all data from 'products' sheet (contains 5 columns):
Then, the script will start adding each country codes from 'cheat' sheet, as seen below, to every group of data from the 'products' sheet:
To run the script, you can click the "Refresh output sheet > Refresh" menu on your Spreadsheet:
To be able to dynamically update your 'output' sheet, you need to create a time-based trigger on the Apps Script editor, like this one that I've created to run the showResult() every 1 minute:
RESULT
On the 'output' sheet, this will be the result:
If there's a new 'product' data, it will be updated to the 'output' sheet as seen here:
I live oversees (military) and get emails when I have a package that arrives at my Post Office and is ready for pickup. I have a Zapier PARSER email account and associated ZAP setup that pulls the data from the email and updates a Google Sheets document with its shelf location, tracking number, and a few other important things from the email so the clerks can get my stuff quickly. It works great. In that same workbook, I have another sheet that I update using an app on my phone to scan tracking barcodes to when I physically pick up the package. On the first sheet I have a basic VLOOKUP function that looks for the tracking number in the scanned list to mark it off as PICKED UP (I get a lot of packages )
I have to manually go in and drag the function down when the ZAP creates a new row. it's not difficult, but i want to have it all automatic. that's what computers are for! I created a google script from the SCRIPT editor on my sheet to do it (I think)
function onEdit(e)
{
var row = e.range.getRow(); //Determine the Row # Just added
var sheet = e.range.getSheet(); //Determine the Sheet, probably not needed
var row_string = row.toString(); //Convert the Row Number to a string.
var start_string = "=VLOOKUP(B"; //this is a fixed part of the function I need in the E column of this row.
var end_string = ", 'Scanned Packages Fixed'!A:B, 2, FALSE)"; //This is the fixed part of the function at the end of the row.
var set_lookup_cell = start_string.concat(row_string, end_string); //Smash the strings together to build a full function
sheet.getRange(row,5).setValue(set_lookup_cell); //Put the full function of the string into the proper cell (E)
}
I am not 100% up on how this would get called automatically or if I am missing a way to link it to the sheet itself. When I hit "run" on the code I got this:
TypeError: Cannot read property 'range' of undefined (line 3, file "Code")
I went into my sheet and just added something in the first column of a new row to see what happened, nothing did.
Any help would be super appreciated!
EDIT: Basically, I need Column E of the row to say this
=VLOOKUP(B63, 'Scanned Packages Fixed'!A:B, 2, FALSE) [Where 63 is the row#]
Turns out, the code above does work. I am just not patient and didn't let the sheet update and script run automatically after an update to a row.
Turns out, this isn't triggered when the zap populates the sheet... Only if I do.
I recently made a script to get info from the Adwords API report KEYWORDS_PERFORMANCE_REPORT that outputed the information to a google sheet and it worked fine.
I decided to make another report for extensions all i basically did was copy and past the old code changing the URL for the google sheet and which report it should use PLACEHOLDER_REPORT instead of the keyword one, as well as some of the metrics.
The script runs without saying that anything is wrong but it doesn't output the values to where its supposed to, or at all for that matter.
function processAccount()
{
var report = AdWordsApp.report(
"SELECT AccountDescriptiveName, CampaignName, ExtensionPlaceholderCreativeId, ExtensionPlaceholderType " +
"FROM PLACEHOLDER_REPORT " +
"WHERE CampaignStatus = ENABLED " +
"DURING LAST_7_DAYS",
{apiVersion: 'v201705'});
var rows = report.rows();
if (rows.hasNext())
{
writeReport(rows);
}
}
function writeReport(rows)
{
var spreadsheet = validateAndGetSpreadsheet(URL);
// Clear all rows in the Details tab of the spreadsheet below the header row.
var clearRange = spreadsheet.getRangeByName('Headers')
.offset(1, 0, spreadsheet.getSheetByName('Details')
.getDataRange().getLastRow())
.clearContent();
// Build each row of output values in the order of the Report tab columns.
var outputValues = [];
while (rows.hasNext())
{
var row = rows.next();
outputValues.push([
row["AccountDescriptiveName"],
row["CampaignName"],
row["ExtensionPlaceholderCreativeId"],
row["ExtensionPlaceholderType"],
]);
}
// Find the first open row on the Report tab below the headers and create a
// range large enough to hold all of the failures, one per row.
var lastRow = spreadsheet.getSheetByName('Details')
.getDataRange().getLastRow();
var headers = spreadsheet.getRangeByName('Headers');
var outputRange = headers
.offset(lastRow - headers.getRow() + 1, 0, outputValues.length);
Logger.log("outputValue length is "+outputValues.length);
outputRange.setValues(outputValues);
Logger.log(outputValues[0]);
spreadsheet.getRangeByName('Date').setValue(new Date());
}
I know its finding the sheet because it clears the rows below the header like its supposed to and puts the date and time when it is run.
The logger shows that outputValue has a length of 293 so its definitly getting stuff and also logs the stuff at outputValue[0] so i dont know why it wont write to the sheet.
I called the adwords helpline but they said thearen't't trained in the api stuff so they don't know whats up, and i've googled it with no success
Everytime it runs you just want the new values, so I suggest using
spreadsheet.getRange(1, 1, data.length, 4).setValues(outputValues);
Replace your last line with this one, the last arguments is how many columns you will write, so in your case is 4, also change your code's logic so it will write the values in the end, not at every iteration!
Turns out i had messed up the output range it was outputting it about 120 rows lower than it was supposed toi do if id just scrolled down i would of seen it. fixed that and now all is fine.
I was trying to make a script for a google spreadsheet that would remove duplicate entries that were submitted via a google form. Essentially the google form writes the entries to the google spreadsheet and I wanted any google form entry that were a duplicate to an entry already submitted through the form, to be removed automatically. This is the code that I have now:
function onFormSubmit(e) {
var sheet = SpreadsheetApp.openById("13ggBeSGGxhI291uPcIr0RudwxxKUigtNEN750Q2hCBM");
var data = sheet.getDataRange().getValues();
var newData = new Array();
for(i in data){
var row = data[i];
var duplicate = false;
for(j in newData){
if(row.join() == newData[j].join()){
duplicate = true;
}
}
if(!duplicate){
newData.push(row);
}
}
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
I know parts of it are still incorrect so i was hoping someone could help me get a better idea of what I'm doing wrong so that I can make the necessary corrections. Thanks!
You opened a Spreadsheet object, you also need to open the actual sheet (One spreadsheets has one or more sheets).
The sheet class has a method clearContents(), a spreadsheet doesn't.
Try SpreadsheetApp.openById("13ggBeSGGxhI291uPcIr0RudwxxKUigtNEN750Q2hCBM").getSheetByName(whateverYourResponseSheetNameIsAsAString);.
As for why the Spreadsheet class supports getValues() but not clearContents(), I don't know, it seems inconsistent. For the former it is implicitly running getActiveSheet().
I already have a spreadsheet that submitted by 3rd party apps (which I can't change its code).
Then, I need to send HTTP (Post) automatically to http://THISISMYURL.url/go.aspx?fieldone=xxx&fieldtwo=xxx when my Google spreadsheet updated.
What in my mind is to create a script in Google Spreadsheet and use UrlFetchApp in my code.
function SendHTTPpost() {
//How to pick data from any field in last column (everytime google spreadsheet updated)?
var data =
{
"fieldOne" : "value for field one (from last column)",
"fieldTwo" : "value for field two (from last column)",
};
var options =
{
"method" : "post",
"payload" : data
};
UrlFetchApp.fetch("http://THISISMYURL.url/go.aspx", options);
}
I know that I missed some command which to fetch some data from spreadsheet. Anybody get some idea to do this?
Thanks for helping me :)
Thanks to #Mogsdad for giving a clue for me. And thanks to #Zig Mandel for suggesting me to read spreadsheetApp documentation.
Here are what I did in my code, and it's works!
// get the spreadsheet object
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// set the first sheet as active
SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
// fetch this sheet
var sheet = spreadsheet.getActiveSheet();
// figure out what the last row is
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
At the last command, I use UrlFetchApp classes by fetch(url) method that I learn from here
Thanks to all for helping me.
And hopefully it will help others too.
Yeay!!!