This question is related to Google-Sheets App Script
I am trying to compare two values from the source sheet to two values in
target sheet respectively then based on the row number found in the
target sheet I want to change the font colour of this cell to that of
the font-clour of the cell found in column-E of the target sheet.
My Logic is shown below.
SrcSheet = Batches-sheet
TargetSheet = Activity-sheet
if srcDate is found in the targetDateRange in TargetSheet AND if
srcBatchName is found in the targetBatchNameRange in TargetSheet THEN
set the font-colour of this cell (srcDate in srcSheet) to the
fontcolour of targetLessonCell of in TargetSheet
My Function definition and Function Call looks like this;
Function Call:
=updateBatchActivity(W18,Activity!B1:B700,I18,Activity!E1:E700)
Function Definition:
function updateBatchActivity() {
var app = SpreadsheetApp;
var sourceSheet = app.getActiveSpreadsheet().getSheetByName("Batches");
var targetSheet = app.getActiveSpreadsheet().getSheetByName("Activity");
for (var srcRow=3; srcRow<=8; srcRow++) {
srcBatch = sourceSheet.getRange(srcRow,9).getValue()
Logger.log('Row ' + srcRow + ' BatchName: ' + srcBatch);
for (var srcCol=21;srcCol<=36; srcCol++) {
var range = sourceSheet.getRange(srcRow,srcCol);
srcDate = range.getValue()
for (var dstRow=2; dstRow<=10; dstRow++) {
var targetDate = targetSheet.getRange(dstRow,2).getValue();
if (srcDate == targetDate) {
var targetBatch = targetSheet.getRange(dstRow,5).getValue();
if (srcBatch == targetBatch) {
var fontColour = targetSheet.getRange(dstRow,6).getFontColour();
range.setFontColor(fontColour);
}
}
}
}
}
}
Related
I am trying to activate the cell in column A of the next empty row in my Google sheet.
I have created the below script based on a video of youtube - this does return the value of the next empty row but I am struggling on how to activate the selection.
Can anyone help on this please?
function jumpToLastRowChilled() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Chilled Sheet");
var rng = ss.getRange("A1:H").getValues();
var lrIndex;
for(var i = rng.length-1;i>=0;i--){
lrIndex = i;
if(!rng[i].every(function(c){ return c == ""})){
break;
}
}
var lr = lrIndex + 2;
}
I found to do this you can do the below:
function jumpToLastRowChilled() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Chilled Sheet");
var rng = ss.getDataRange();
var lr = rng.getLastRow();
var alr = ss.getRange(lr+1,1).activate();
}
I am trying to copy data from one sheet, paste it into another and then delete the row that have a "flag" attached to them (Column D). When I execute this code, it just deletes the flag and not the whole row. What is going on here? The functions seem to execute in the wrong order.
Tried using Utilities.sleep(), as well as
separating both into different functions
using a for loop writing out all the columns I want deleted
applying flush to the functions before executing the next
//copies the code
function myFunction() {
var url = 'https://docs.google.com/spreadsheets/d/1ie2Fyj2piVV8XC0XUGX-fTAHcQ0UUUdec4Mtr1QdXtQ/edit#gid=293227072'
var ss = SpreadsheetApp.openByUrl(url)
var sheet = ss.getSheetByName('Bad Emails Input')
var range = sheet.getRange("K:N")
var values = range.getValues()
var target = ss.getSheetByName("worklist")
target.getRange("A:D").setValues(values)
SpreadsheetApp.flush()
Utilities.sleep(5 * 1000)
}
//deletes the rows with flags in them
function myFunction2() {
var url = 'https://docs.google.com/spreadsheets/d/1ie2Fyj2piVV8XC0XUGX-fTAHcQ0UUUdec4Mtr1QdXtQ/edit#gid=293227072'
var ss = SpreadsheetApp.openByUrl(url)
var sheet = ss.getSheetByName('Bad Emails Input')
var range = sheet.getRange("K:N")
var values = range.getValues()
var target = ss.getSheetByName("worklist")
Utilities.sleep(6 * 1000)
var oldnews = target.getRange("D:D")
for (i = oldnews.length; i > 0; i--){
if (oldnews[i] !== undefined) {
target.getRange(i,1)
target.getRange(i,2)
target.getRange(i,3)
target.getRange(i,4)
}
}
SpreadsheetApp.flush()
}
It's not really clear what your asking. So I just guessed at some of this.
function myFunction() {
var ss = SpreadsheetApp.openById("id");
var sheet = ss.getSheetByName('Bad Emails Input')
var range = sheet.getRange(1,11,sheet.getLastRow(),4);
var values = range.getValues()
var target = ss.getSheetByName("worklist")
target.getRange(1,1,values.length,values[0].length).setValues(values);
SpreadsheetApp.flush();
var d=0;
for(var i=0;i<values.length;i++) {
if(values[i][3]) {
target.deleteRow(i+1-d++);
}
}
}
Try the below code:
function myFunction() {
var url = 'https://docs.google.com/spreadsheets/d/1ie2Fyj2piVV8XC0XUGX-fTAHcQ0UUUdec4Mtr1QdXtQ/edit#gid=293227072'
var ss = SpreadsheetApp.openByUrl(url);
var sheet = ss.getSheetByName('Bad Emails Input');
var range = sheet.getRange("K:N");
var values = range.getValues();
var target = ss.getSheetByName("worklist");
target.getRange("A:D").setValues(values);
SpreadsheetApp.flush();
//If you have a header row change the below to A2:D and count to 2
var data=ss.getSheetByName("worklist").getRange("A:D").getValues(),count=1;
for (i in data) {
var rowdata=data[i];
if (!rowdata[0] || rowdata[0]==''){break;}
if (rowdata[3] == 'flag') {//change the flag to however it is in column D
ss.getSheetByName("worklist").deleteRow(count);
count++;
}
}
}
I'm trying to.. 1) replace a substring from the contents of the active cell in my sheet, and.. 2) move the active cell down one spot, and repeat until the active cell value is empty. Here's my function, but nothing happens when I run it...can anyone see why?
var app = SpreadsheetApp;
var mySheet = ss.getSheetByName('NAME');
var activeCell = mySheet.getActiveCell();
var cellValue = activeCell.getValue();
var activeRow = activeCell.getRow();
function replaceStringInCell(){
while(cellValue != ''){
var newCellValue = cellValue.replace('MC/Visa/Discover', 'CC');
activeCell.setValue(newCellValue);
activeRow++;
mySheet.getRange(activeRow, 7).activate();
}
}
Issue:
Unnecessary looping over each cell
Solution:
Use batch operations
Sample Script:
function replaceColA() {
var ss = SpreadsheetApp.getActive();
var mySheet = ss.getSheetByName('NAME');
var cellRange = mySheet.getRange('A1:A' + mySheet.getLastRow());
var cellValues = cellRange.getValues().map(replaceStringInCell); //call replace function on all values in range
cellRange.setValues(cellValues); //set mapped values back to range
}
function replaceStringInCell(cellValue) {
if (cellValue.map) {
//if cellValue is a array
return cellValue.map(replaceStringInCell); //recurse
} else {
return cellValue.replace('MC/Visa/Discover', 'CC');
}
}
To Read:
Arrays
Array#Methods
Array#2DFromSpreadsheets
Array#map
String#replace
I have written a script to clean up and move data between 3 different sheets. A user first paste a data extract on to the "Extract" page, and then runs the script.
When a user paste the data into cell A1 on the "Extract" page, I would like a prompt box to ask the user if they would like to run the script; if Yes, run script, if No, don't run script and show message. How would I go about doing this?
This is what I have so far...everything after the first function works.
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Extract");
if(ss.s().getRange("A1").getValue() != ""){
var ui = SpreadsheetApp.getUi()
var response = ui.alert('Would you jbot to find new claims for you?', ui.ButtonSet.OK_CANCEL);
if (response == ui.Button.OK) {
jbot();
} else {
Logger.log('The user clicked "No" or the close button in the dialog\'s title bar.');
}
}
}
function jbot(){
movetobot();
deleteRows();
removeDupesInOtherSheets();
deleteCol();
cleanup();
movetoqueue();
message();
};
function movetobot() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Extract");
var ts = ss.getSheetByName("bot");
s.getRange("A1:BW").moveTo(ts.getRange("A1"));
}
function deleteRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("bot");
var r = s.getRange("BO:BO");
var v = r.getValues();
for(var i=v.length-1;i>=0;i--)
if(v[0,i]=='#POSTLESSEE' || v[0,i]=='#TDI CRC_OANKURA' || v[0,i]=='#Partpaymentoffer' || v[0,i]=='#TDI_CRC_DVANKURA' || v[0,i]=='#partpaymentdupe' )
s.deleteRow(i+1);
}
function removeDupesInOtherSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s1 = ss.getSheetByName("bot").getDataRange().getValues();
var s2 = ss.getSheetByName("Queue").getDataRange().getValues();
// iterate 'Queue' and check in 'bot' if duplicate values exist
var nS1 = [];
var s2Col1 = [];// data in column1 of Queue
for(var n in s2){
s2Col1.push(s2[n][0]);
}
for(var n in s1){ // iterate '180418970' and test col 1 vs col 1 in 'Queue'
var noDup1 = checkForDup(s1[n],s2Col1)
if(noDup1){nS1.push(noDup1)};// if not present in 'Queue' then keep
}
Logger.log(nS1);// view result
ss.getSheetByName("bot").getDataRange().clear();// clear and update sheets
ss.getSheetByName("bot").getRange(1,1,nS1.length,nS1[0].length).setValues(nS1);
}
function checkForDup(item,s){
Logger.log(s+' = '+item[0]+' ?')
if(s.indexOf(item[0])>-1){
return null;
}
return item;
}
function deleteCol() {
var spread = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spread.getSheetByName("bot");
var lastCol = sheet.getLastColumn();
var keep = [1,2,3,4,45,53,74, 75]; // array of column numbers to keep
for (var col=lastCol; col > 0; col--) {
if (keep.indexOf(col) == -1) {
// This isn't a keeper, delete it
sheet.deleteColumn(col);
}
}
}
function cleanup() {
var spread = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spread.getSheetByName("bot");
sheet.getRange("B1:B").moveTo(sheet.getRange("H1"));
sheet.deleteColumn(2)
sheet.deleteRow(1)
var cell = sheet.getRange("D:D");
cell.setNumberFormat("m/d/yy");
var cell = sheet.getRange("F:F");
cell.setNumberFormat("m/d/yy");
var cell = sheet.getRange("A:A");
cell.setHorizontalAlignment("center");
var cell = sheet.getRange("C:D");
cell.setHorizontalAlignment("center");
var cell = sheet.getRange("F:G");
cell.setHorizontalAlignment("center");
sheet.autoResizeColumn(2)
sheet.autoResizeColumn(5)
sheet.autoResizeColumn(7)
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spread.getSheetByName("bot");
var cell = sheet.getRange("BW1");
cell.setFormula("=COUNT(A:A)");
var spread = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spread.getSheetByName("bot");
var range = sheet.getRange("A1:G");
range.sort({column: 4, ascending: true})
}
function movetoqueue() {
var spread = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spread.getSheetByName("bot");
// skip row 1 (header) and beyond column G
var range = sheet.getRange(1,1,sheet.getLastRow()-1,7);
sheet = spread.getSheetByName("Queue");
var rows = sheet.getRange(1,1,sheet.getLastRow(),1).getValues();
// search for first blank row column 1
for( var i=0; i<rows.length; i++ ) {
if( rows[i][0] === "" ) {
var offset = sheet.getRange(1,1).offset(i,0);
range.copyTo(offset);
break;
}
}
}
function message() {
SpreadsheetApp.getActive().getSheetByName("Queue").activate();
var spread = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spread.getSheetByName("bot");
var range = sheet.getRange("bot!BW1:BW1");
var data = range.getValue();
Browser.msgBox(data + " new claims have been added to the queue. Thank you for using jBot!");
}
Your onEdit(e) will trigger the alert regardless of which cell is edited. You need to check the event range to limit it to cell A1 of Extract like this.
function onEdit(e) {
if( e.range.getSheet().getName() === "Extract" ) {
if( e.range.getA1Notation() === "A1" ) {
if( e.value !== "" ) {
var ui = SpreadsheetApp.getUi();
// Do the rest of your stuff here
}
}
}
}
I have a source cell with the range name "source".
I have some target (non-adjacent) cells with the range names "target1", "target2", "target3".
If the cell "source" is changed, I want the value of it to be copied into the 3 target cells.
I'm stumbling at the first hurdle in that I cannot work out how to test if I'm editing the "source" cell.
All the documentation seems to be about naming ranges rather than then working with them.
So far I have...
function onEdit()
{
var sh = SpreadsheetApp.getActiveSheet();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getActiveRange();
var C = range.getColumnIndex();
var a = sh.getActiveCell();
if( range == "LXbar1" )
{
SpreadsheetApp.getUi().alert('You are HERE!');
}
}
revised code:
function onEdit(e)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Active range
var eventRange = e.range;
// Active range address
var eventRangeA1 = eventRange.getSheet().getName() + "!" + eventRange.getA1Notation();
// Comparison range name
var sourceRange = ss.getRangeByName("rLXbar1");
// Comparison range address
var sourceRangeA1 = sourceRange.getSheet().getName() + "!" + sourceRange.getA1Notation();
if (eventRangeA1 === sourceRangeA1)
{
// Target range name
var targetRange = ss.getRangeByName("rLamp08");
targetRange.setValue(sourceRangeA1.value);
}
}
Don't use Active elements in onEdit triggers, use the built in event object it will ensure it will always use the actually selected cell when the edit happened.
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var eventRange = e.range;
var sourceRange = ss.getRangeByName("source");
var eventRangeA1 = eventRange.getSheet().getName() + "!" + eventRange.getA1Notation();
var sourceRangeA1 = sourceRange.getSheet().getName() + "!" + sourceRange.getA1Notation();
if (eventRangeA1 === sourceRangeA1) {
SpreadsheetApp.getUi().alert("You are HERE!");
}
};