I need some assistance with Google Apps Script. I am working in google sheets and currently have the following script:
function transpose() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('C3:N3').activate();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Sheet21'), true);
spreadsheet.getRange("'A/P'!C3:N3").copyTo(spreadsheet.getActiveRange(),
SpreadsheetApp.CopyPasteType.PASTE_NORMAL, true);
};
Rather than just paste in A1 of Sheet 21, I would like it to find the bottom of column F. I am also wondering how to copy data from whichever sheet I am in, not just the sheet named A/P.
Thank you in advance!
You want to add the values of C3:N3 in the active sheet to the next row of last row on column F in Sheet21. If my understanding is correct, how about this modification?
Modification points :
In your script, if the active sheet is not Sheet21, the active range becomes "A1", because spreadsheet.getRange('C3:N3').activate() at other sheet is changed by spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Sheet21'), true). By this, the values of "'A/P'!C3:N3" are copied for "A1" of Sheet21.
Flow of modified script:
Retrieve the range of source (Active sheet)
Retrieve the destination (Sheet21) sheet.
Retrieve the destination range.
Copy
Modified script : Pattern 1
If the address of last row of column "F" in "Sheet21" is smaller than that of other columns, please use this.
function transpose() {
var spreadsheet = SpreadsheetApp.getActive();
var srcRange = spreadsheet.getActiveSheet().getRange('C3:N3');
var dstSheet = spreadsheet.getSheetByName('Sheet21');
var range = dstSheet.getRange('F1:F');
var values = range.getValues();
var formulas = range.getFormulas();
var i;
for (i = values.length - 1; i >= 0; i--) {
if (values[i][0] != "" || formulas[i][0] != "") break;
}
var dstRange = dstSheet.getRange("F" + (i + 2));
srcRange.copyTo(dstRange, SpreadsheetApp.CopyPasteType.PASTE_NORMAL, true);
};
Modified script : Pattern 2
If the address of last row of column "F" in "Sheet21" is larger or the same with that of other columns, please use this.
function transpose() {
var spreadsheet = SpreadsheetApp.getActive();
var srcRange = spreadsheet.getActiveSheet().getRange('C3:N3');
var dstSheet = spreadsheet.getSheetByName('Sheet21');
var dstRange = dstSheet.getRange("F" + (dstSheet.getLastRow() + 1));
srcRange.copyTo(dstRange, SpreadsheetApp.CopyPasteType.PASTE_NORMAL, true);
};
If I misunderstand your question, please tell me. I would like to modify it.
Related
I am very new to Google Appscript and support of this community will really be appreciated. Using different posts on the Stakeoverflow community I had designed an appscript to copy and paste the data from one worksheet to another and this is working fine (the data of worksheet named Copy is paste in worksheet named Paste). I had also created a worksheet named Trigger and in that I had created a dropdown in cell A1, now I want my script to run every time when the dropdonw in this sheet is changed. I had checked the different solutions on this community but as am new to appscirpt could not design a perfect solution to my case. Below is the link to the sheet and my current script.
https://docs.google.com/spreadsheets/d/1xy5eN8_PHXi9RPWK_EKg99dylaDjQ9lcilrSW0GP4B0/edit#gid=0
function Referesh() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Copy");
var pasteSheet = ss.getSheetByName("Paste");
var source = copySheet.getRange(2,1,copySheet.getLastRow(),2);
var rub = copySheet.getRange(2,1,copySheet.getLastRow(),2);
var destination =
pasteSheet.getRange(pasteSheet.getLastRow()+1,2,copySheet.getLastRow(),2);
source.copyTo((destination), {contentsOnly: true});
rub.clearContent();
console.log(pasteSheet.getLastRow());
}
Any help on above will be appreciated.
I believe your goal is as follows.
You want to automatically run your script by changing the dropdown list of the cell "A1" of "Trigger" sheet.
In this case, how about using the OnEdit simple trigger as follows?
Modified script:
Please copy and paste the following script to the script editor of Spreadsheet and save the script. When you use this script, in this case, please change the dropdown list of the cell "A1" of "Trigger" sheet to "Run". By this, the script is run.
function onEdit(e) {
var sheetName = "Trigger";
var runScript = "Run";
var { range, source, value } = e;
var sheet = range.getSheet();
if (sheet.getSheetName() != sheetName || range.columnStart != 1 || range.rowStart != 1 || value != runScript) return;
var ss = source;
var copySheet = ss.getSheetByName("Copy");
var pasteSheet = ss.getSheetByName("Paste");
var source = copySheet.getRange(2, 1, copySheet.getLastRow(), 2);
var rub = copySheet.getRange(2, 1, copySheet.getLastRow(), 2);
var destination = pasteSheet.getRange(pasteSheet.getLastRow() + 1, 2, copySheet.getLastRow(), 2);
source.copyTo((destination), { contentsOnly: true });
rub.clearContent();
console.log(pasteSheet.getLastRow());
range.setValue("Refresh"); // By this script, the value of "Run" is changed to "Refresh".
}
Note:
It seems that there are 2 values of Run and Refresh in your dropdown list. Unfortunately, I couldn't know the trigger value. So, in this sample script, when the dropdown list is changed to Run, the script is run by the simple trigger. If you want to change this, please modify the above script.
When you run directly onEdit with the script editor, an error occurs because of no event object. So, please be careful about this.
If you want to ignore the trigger value, I think that the following script might be able to be used. In this case, the dropdown list is changed, the script is run.
function onEdit(e) {
var sheetName = "Trigger";
var { range, source } = e;
var sheet = range.getSheet();
if (sheet.getSheetName() != sheetName || range.columnStart != 1 || range.rowStart != 1) return;
var ss = source;
var copySheet = ss.getSheetByName("Copy");
var pasteSheet = ss.getSheetByName("Paste");
var source = copySheet.getRange(2, 1, copySheet.getLastRow(), 2);
var rub = copySheet.getRange(2, 1, copySheet.getLastRow(), 2);
var destination = pasteSheet.getRange(pasteSheet.getLastRow() + 1, 2, copySheet.getLastRow(), 2);
source.copyTo((destination), { contentsOnly: true });
rub.clearContent();
console.log(pasteSheet.getLastRow());
}
Reference:
Simple Triggers
I have the following problem with this function. It only deletes blank rows below but I want to delete the rows above.
function removeEmptyRows(){
var sh = SpreadsheetApp.getActive();
var sh1=sh.getSheetByName('name');
var range=sh1.getRange('A:A');
var maxRows = sh1.getMaxRows();
var lastRow = sh1.getLastRow();
sh1.deleteRows(lastRow+1, maxRows-lastRow);
}
I tried with the following function
function removeemptyrows(){
var ss=SpreadsheetApp.getActive();
var sh1=ss.getSheetByName('name');
var range=sh1.getRange('A:A');
var values = range.getValues();
for( var i = values.length-1; i >=0; i-- ) {
for( var j = 0; j < values[i].length; j++ )
if( values[i][j] === "" )
sh1.deleteRow(i+1)
}
}
but it deletes rows too slowly - one by one.
You want to delete the rows that the cell of column "A" is empty in the range from 10 row to bottom of sheet.
You want to achieve this using Google Apps Script.
You want to reduce the process cost.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification point:
In this case, I would like to propose to use Sheets API. When Sheets API is used, the rows can be deleted by one API call, even when the rows are discreted.
Sample script:
When you use this script, please enable Sheets API at Advanced Google services.
function removeemptyrows() {
var sheetName = "name"; // Please set the sheet name.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetName);
var sheetId = sheet.getSheetId();
var values = sheet.getRange('A10:A').getValues();
var requests = values.reduce(function(ar, [e], i) {
if (!e) ar.push({deleteDimension:{range:{sheetId:sheetId,dimension:"ROWS",startIndex:(i + 9),endIndex:(i + 10)}}});
return ar;
}, []).reverse();
if (requests.length > 0) Sheets.Spreadsheets.batchUpdate({requests: requests}, ss.getId());
}
In this case, the sample script is almost the same with the below script of https://stackoverflow.com/a/60613983/7108653 . As 2 modification parts, in your case, you want to delete the rows of empty cell at the column "A". So 'C6:C' + sheet.getLastRow() and if (e) were modified to 'A10:A' and if (!e), respectively.
References:
Method: spreadsheets.batchUpdate
Advanced Google services
If I misunderstood your question and this was not the direction you want, I apologize.
My code below works, but I thinking that there's a much more elegant way of doing it. I want to copy a portion of a selected row (D:R) on the Customer sheet (source) to the Test sheet (destination) to the first blank row in that sheet (C:Q).
The code works, but just looks non-performant/non-elegant.
function rowSelected() {
var customer_sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Customer_Info");
var invoice_sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test");
var customer_selection_row = customer_sheet.getActiveRange().getRow();
//Browser.msgBox(customer_selection_row);
var customer_selection_start = 'D' + customer_selection_row;
var customer_selection_end = 'R' + customer_selection_row;
var customer_selection_range = customer_selection_start + ':' + customer_selection_end;
var source_range = customer_sheet.getRange(customer_selection_range);
customer_sheet.setActiveRange(source_range);
//Browser.msgBox(source_range.getA1Notation());
var invoice_selection_row = getFirstEmptyRowWholeRow();
var invoice_selection_start = 'C' + invoice_selection_row;
var invoice_selection_end = 'Q' + invoice_selection_row;
var invoice_selection_range = invoice_selection_start + ':' + invoice_selection_end;
var destination_range = invoice_sheet.getRange(invoice_selection_range);
invoice_sheet.setActiveRange(destination_range);
//Browser.msgBox(destination_range.getA1Notation());
customer_sheet.setActiveRange(source_range).copyTo((destination_range), {contentsOnly:true});
}
I'm thinking there is some way of doing this with less code.
You want to copy the column "D" to "R" at the row of the active range of the sheet Customer_Info to the column "C" to "Q" at the row retrieved by getFirstEmptyRowWholeRow() of the sheet Test.
You want to activate the source range.
If my understanding is correct, how about this modification?
Modification points:
SpreadsheetApp.getActiveSpreadsheet() is declared one time as `ss``.
getRange(row, column, numRows, numColumns) is used instead of getRange(a1Notation).
About destination_range, when the start cell is set, the source range can be copied from it.
When the active sheet is Customer_Info, the script is run.
Modified script:
function rowSelected() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var customer_sheet = ss.getActiveSheet();
if (customer_sheet.getSheetName() == "Customer_Info") {
var invoice_sheet = ss.getSheetByName("Test");
var activeRange = ss.getActiveRange();
var source_range = customer_sheet.getRange(activeRange.getRow(), 4, activeRange.getNumRows(), 15).activate();
var destination_range = invoice_sheet.getRange(getFirstEmptyRowWholeRow(), 3); // or invoice_sheet.getRange("C" + getFirstEmptyRowWholeRow())
source_range.copyTo(destination_range, {contentsOnly: true});
}
}
getFirstEmptyRowWholeRow() of your script is also used for above modified script.
In this modified script, if you want to select the range of "A1:A3" on the sheet Customer_Info and run the script, the values of cells "D1:R3" are copied from the cell of the column "C" and the row of getFirstEmptyRowWholeRow().
References:
getRange(row, column, numRows, numColumns)
activate()
If I misunderstood your question and this was not what you want, I apologize.
In this spreadsheet: https://docs.google.com/spreadsheets/d/1givNbMvgzD8lbk6NAcwjkpp4-A_D8MetltHjEpinOAI/edit#gid=0
I'd like to Combine only unique Links and Category into Combined sheet.
Right now, with my script, it can only combine all existing data:
function combine() {
var ss = SpreadsheetApp.getActive();
var allsheets = ss.getSheets();
var sourceID = '1givNbMvgzD8lbk6NAcwjkpp4-A_D8MetltHjEpinOAI';
var targetID = '1givNbMvgzD8lbk6NAcwjkpp4-A_D8MetltHjEpinOAI';
var sheetExclude = ["Combined"];
var sheetExcludeIndex = new Array(sheetExclude.length);
for (var s in allsheets) {
var sheet = allsheets[s];
for (var e in sheetExclude) {
if (String(sheet.getName() == sheetExclude[e])) {
sheetExcludeIndex[e] = sheet.getIndex;
}
}
}
allsheets.splice(sheetExcludeIndex, sheetExclude.length);
for (var s in allsheets) {
var sheet = allsheets[s];
updateSourceToTarget(sourceID, sheet.getName(), targetID, 'Combined');
}
}
function updateSourceToTarget(sourceID, sourceName, targetID, targetname) {
Logger.log(sourceID + ' ' + sourceName + ' ' +targetname);
var source = SpreadsheetApp.openById(sourceID).getSheetByName(sourceName);
var destination = SpreadsheetApp.openById(targetID).getSheetByName(targetname);
var sourcelastRow = source.getLastRow();
var sourcelastCol = source.getLastColumn();
var destinationlastRow = destination.getLastRow();
var destinationlastCol = destination.getLastColumn();
var sourcedata = source.getRange(2, 9, sourcelastRow, 10).getValues();
destination.getRange(destinationlastRow + 1, 2, sourcelastRow, sourcelastCol).setValues(sourcedata);
}
However, I'd like to only combine unique links from Sheet2 and Sheet3:
In red is unique data
Sheet2:
Sheet3:
How can I efficiently add only unique values to Combined from Sheet2& Sheet3?
You want to put the values, which removed the duplicated links, to the target sheet (in this case, it's Combined sheet.).
The duplicated links are checked from the target sheet and source sheets. In this case, the target sheet and source sheets are Combined, Sheet2 and Sheet3, respectively.
In your sample Spreadsheet, you want to put the following rows to the target sheet.
https://thehill.com/policy/national-security/department-of-homeland-security/460158-new-hampshire-border-patrol BorderSecurity
https://abcnews.go.com/International/climate-change-frontier-worlds-northernmost-town/story?id=65381362 ClimateChange
You want to achieve this by modifying your Google Apps Script.
If my understanding is correct, how about this modification? Please think of this as just one of several answers.
Modified script:
Please modify your script as follows. In this modification, your function of updateSourceToTarget() is not used.
From:
for (var s in allsheets) {
var sheet = allsheets[s];
updateSourceToTarget(sourceID, sheet.getName(), targetID, 'Combined');
}
To:
// Retrieve values from the target sheet.
var targetSheet = ss.getSheetByName(sheetExclude[0]);
var targetValues = targetSheet.getRange("B2:C" + targetSheet.getLastRow()).getValues();
// Retrieve values from all source sheets. <--- Modified
var sourceValues = allsheets.reduce(function(ar, sheet) {
var v = sheet.getRange(2, 9, sheet.getLastRow() - 1, 10).getValues().filter(function(r) {return r[0] && r[1]});
if (v.length > 0) {
v = v.filter(function(e) {return !ar.some(function(f) {return e[0] === f[0]})});
Array.prototype.push.apply(ar, v);
}
return ar;
}, []);
// Remove the duplication values between the target sheet and all source sheets.
var dstValues = sourceValues.filter(function(e) {return !targetValues.some(function(f) {return e[0] === f[0]})});
// Add the result values to the target sheet.
if (dstValues.length > 0) {
var destination = SpreadsheetApp.openById(targetID).getSheetByName(sheetExclude[0]);
destination.getRange(destination.getLastRow() + 1, 2, dstValues.length, dstValues[0].length).setValues(dstValues);
}
The flow of this modified script is as follows.
Retrieve values from the target sheet.
Retrieve values from all source sheets.
Remove the duplication values between the target sheet and all source sheets.
Add the result values to the target sheet.
Note:
When your shared Spreadsheet is used as the target (Combined) and source sheets (Sheet2 and Sheet3), the following rows are added to the target sheet.
https://thehill.com/policy/national-security/department-of-homeland-security/460158-new-hampshire-border-patrol BorderSecurity
https://abcnews.go.com/International/climate-change-frontier-worlds-northernmost-town/story?id=65381362 ClimateChange
References:
reduce()
filter()
some()
If I misunderstood your question and this was not the direction you want, I apologize.
Added:
In this additional script, a hash table is used for this situation, as mentioned by TheMaster's comment. For example, a sample can be also seen at this thread. In your situation, at first, all values are retrieved from all sheets including Combined sheet, and the hash table is created. By this, the duplicated values are removed. Then, the converted values to an array are put to the Spreadsheet.
Sample script:
Please modify your script as follows.
From:
allsheets.splice(sheetExcludeIndex, sheetExclude.length);
for (var s in allsheets) {
var sheet = allsheets[s];
updateSourceToTarget(sourceID, sheet.getName(), targetID, 'Combined');
}
To:
// allsheets.splice(sheetExcludeIndex, sheetExclude.length); // In this script, this line is not used.
// Retrieve values from the target sheet.
var targetSheet = ss.getSheetByName(sheetExclude[0]);
var targetValues = targetSheet.getRange("B2:C" + targetSheet.getLastRow()).getValues();
// Retrieve values from all source sheets.
// Remove the duplication values between the target sheet and all source sheets.
var sourceValues = allsheets.reduce(function(obj, sheet) {
var v = sheet.getRange(2, 9, sheet.getLastRow() - 1, 10).getValues().filter(function(r) {return r[0] && r[1]});
if (v.length > 0) v.forEach(function(e) {if (!(e[0] in obj)) obj[e[0]] = e[1]});
return obj;
}, {});
var dstValues = Object.keys(sourceValues).map(function(e) {return [e, sourceValues[e]]});
// Add the result values to the target sheet.
if (dstValues.length > 0) {
var destination = SpreadsheetApp.openById(targetID).getSheetByName(sheetExclude[0]);
destination.getRange(2, 2, destination.getLastRow(), 2).clearContent();
destination.getRange(2, 2, dstValues.length, dstValues[0].length).setValues(dstValues);
}
The proposed 2 sample scripts can be used for your situation. So please select one of them.
Hi could someone help me with this script im trying to insert a formula in all the blank cell from (J15) to (J38) here is what ive got but I just cant seem to get it the proper way any help would be greatly appreciated.
function test() {
var ssA = SpreadsheetApp.getActive(); //changed from openById() for my convenience
var ss = ssA.getActiveSheet(); //change from getSheetByName() for my convenience
var range = ss.getRange(15,10,24,1); //row 2 column 7 (G) lastRow 1 column
var data = range.getValues(); //Gets all data
for(var i=0;i<data.length;i++) //this runs over entire selected range
{
if(!data[i][0]) //If true then it's blank
{
data[i](('=Iferror(If(G15="",, if($B$5 = Iferror(query(\'Client
List\'!$A$2:$A, "select A where A =\'"&$B$5&"\'"),""),VLOOKUP($B$5,Client_Rate,2,False),VLOOKUP(D15,Config_Rate_List
,2,False))),"")');)
}
}
range.setFormula(data); //Sets all data.
}
You want to put the formula to "J15:J38". If my understanding is correct, how about this modification?
I thought that it is possible that the cells of "J15:J38" have the values and formulas. So in this modified script, the formula is put to the empty cells which don't have both. The flow of script is as follows.
Retrieve values and formulas from "J15:J38".
Create range list.
Put the formula using setFormula().
I think that there are several solutions for your situation. So please think of this as one of them.
Modified script :
function test() {
var ssA = SpreadsheetApp.getActive(); //changed from openById() for my convenience
var ss = ssA.getActiveSheet(); //change from getSheetByName() for my convenience
var range = ss.getRange(15,10,24,1); //row 2 column 7 (G) lastRow 1 column
var data = range.getValues(); //Gets all data
// The following script was modified.
var formulas = range.getFormulas();
var rangeList = [];
var offset = 15;
for(var i=0;i<data.length;i++) {
if(!data[i][0] && !formulas[i][0]) {
rangeList.push("J" + (offset + i));
}
}
var formula = '=Iferror(If(G15="",, if($B$5 = Iferror(query(\'Client List\'!$A$2:$A, "select A where A =\'"&$B$5&"\'"),""),VLOOKUP($B$5,Client_Rate,2,False),VLOOKUP(D15,Config_Rate_List,2,False))),"")';
ss.getRangeList(rangeList).setFormula(formula);
}
Note :
I was not sure whether the sheet name is Client List or ClientList, because of the line break in your script.
I'm not sure about the formula which was put to cells.
About your title, "black" of "Google Script insert formula in 1 column where cell are black" is "blank"?
Reference :
getRangeList(a1Notations)
If this was not what you want, I'm sorry.
Edit :
Unfortunately, the formulas in an array cannot be put the cells using the range list yet. I think that Sheets API can put various formulas once. But as a simple way, here, I would like to propose the following script.
function test() {
var ssA = SpreadsheetApp.getActive(); //changed from openById() for my convenience
var ss = ssA.getActiveSheet(); //change from getSheetByName() for my convenience
var range = ss.getRange(15,10,24,1); //row 2 column 7 (G) lastRow 1 column
var data = range.getValues(); //Gets all data
// The following script was modified.
var formulas = range.getFormulas();
var val = [];
var offset = 15;
for(var i=0;i<data.length;i++) {
if(!data[i][0] && !formulas[i][0]) {
ss.getRange("J" + (offset + i)).setFormula('=Iferror(If(G' + (offset + i) + '="",, if($B$5 = Iferror(query(\'Client List\'!$A$2:$A, "select A where A =\'"&$B$5&"\'"),""),VLOOKUP($B$5,Client_Rate,2,False),VLOOKUP(D' + (offset + i) + ',Config_Rate_List,2,False))),"")');
}
}
}