Firing a bigQuery query on editing a particular column in google sheets - javascript

/* I am new to app scripting and I have a very specific question. I have a sheet with column A. Whenever this sheet is changed to add/edit the column A, i need to trigger bigQuery query and update results in another column B. I used onedit() function but it does not run the bigQuery query. I also tried using an installable trigger but still no luck. Any advice on how to handle such scenario.
Issue 1: Only top edited row is added to array " dat"
2: The function runBigQuery is not triggered. */
Script:
function onMyEdit(e){
// Trying to find if the edited sheet is 'A' and column is 25. If so, I //want to get edited value(s) in the column 25 and add to an array
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = e.range;
var colZ=range.getColumn()+1;
var dat=[]
if (sheet.getName() == 'A' && range.getColumn() == 25 )
{
for(var i=0;i<range.getNumRows();i++)
{
var offset=range.getRow() + i;
var g=sheet.getRange('Y' + offset).getValue();
var val=sheet.getRange('Z' + offset).getValue();
if (val== "Not found")
{
dat.push(g)
}
}
}
dat = dat.filter(function(n){ return n != "" });
for (var i = 0; i < dat.length; i++)
{
dat[i] = '"' + dat[i] + '"';
}
var unique = [...new Set(dat)]
//Initiate Query by calling function runBigQuery
var values= runBigQuery(unique)
// Append the results to another sheet.
appendData(sheetName,values)
}
Thanks,

Related

How to send full row and list name from Google Sheet, not only specific (fixed) cells and list name?

So I have a script, that sends msg to group chat, if in Column ( 2 ) in any cell's some one printed "Yanson" bot sends only fixed cell - .getRange(row,8). In my case this cell holds link to document.
Bot msg looks like this - Link to document New Added Document List Name ( This time I get List name coz it fixed in var ws, if script work's in another list , I don't receive the right list Name I still receive the fixed one in var ws)
If we delete === ws and print "Yanson" in another list - I'll receive only info from .getRange(row,8) and "Added New Document.
But I need to send full string ( row ) with all the cell inside it, not only cell 8 with link. And I also need to see in msg from bot list name where "Yanson" was printed. Because I have more then 10+ list in Sheet. Sheet looks like this Tablepicture
const token = "Token";
function onEdit(e) {
sendTelegram(e)
}
function sendTelegram(e){
var row = e.range.getRow();
var col = e.range.getColumn();
var startRow = 2; // Starting row
var targetColumn = 2; // If in this column, cell changes to Yanson - send to Telegram
var ws = "List name"; //List name
let chatId = "ChatId";
let Company = e.source.getActiveSheet().getRange(row,8).getValue();
var text = encodeURIComponent(Company + " New Document Added" + ws)
var currentDate = new Date();
var url = "https://api.telegram.org/bot" + token + "/sendMessage?chat_id=" + chatId + "&text=" + text;
if (col === targetColumn && row >= startRow && e.source.getActiveSheet().getName() === ws){
if(e.source.getActiveSheet().getRange(row,2).getValue() == "Yanson"){ //Yanson - Trigger. If Yanson printed in cell in column 2 - send to telegram
sendText(chatId,Company + " New Document Added" +" "+ ws);
//Doing nothig right now.
// e.source.getActiveSheet().getRange(row,4).setValue(currentDate);
// if(e.source.getActiveSheet().getRange(row,3).getValue() == ""){
// e.source.getActiveSheet().getRange(row,3).setValue(currentDate)
// }
}
}
}
Based on what I could gather from your description, you are looking for a way to send the entire contents of the row as a string.
To do that, you get the range of that row, which looks like this:
sheet.getRange(starting row, starting column, # of rows, # of cols)
Sheets uses a two dimensional array that looks like this:
[[row1Col1, row1Col2, row1Col3], [row2Col1, row2Col2, row2Col3], etc]
const token = "Token";
function onEdit(e) {
sendTelegram(e)
}
function sendTelegram(e){
var row = e.range.getRow();
var col = e.range.getColumn();
var startRow = 2; // Starting row
var targetColumn = 2; // If in this column, cell changes to Yanson - send to Telegram
var ws = "List name"; //List name
/*--- Updated this section ----*/
//Adding variables to improve readiblity
var sheet = e.source.getActiveSheet();
var sheetName = e.source.getActiveSheet().getName();
let company = e.source.getActiveSheet().getRange(row,8).getValue();
var listName = ; //Is the list name the same as the sheet name? if not, reference the list names location here
//Define the range of the whole row
var firstCol = 1;
var numOfCols = 8;
var fullRowValues = sheet.getRange(row, firstCol, 1, numOfCols).getValues();
//since this is a single row, you can use .flat() to make it a 1D array
//Then convert it to a string
var fullRowString = fullRowValues.flat().toString();
/*---- End updates ---*/
let chatId = "ChatId";
var text = encodeURIComponent(Company + " New Document Added" + ws)
var currentDate = new Date();
var url = "https://api.telegram.org/bot" + token + "/sendMessage?chat_id=" + chatId + "&text=" + text;
if (col === targetColumn && row >= startRow && sheetName === ws){
if(company == "Yanson"){ //Yanson - Trigger. If Yanson printed in cell in column 2 - send to telegram
// Not sure what the output is supposed to look like,
// so I just added it to the end of your existing output
sendText(chatId,Company + " New Document Added" +" "+ ws + " All Values: " + fullRowString);
//Doing nothig right now.
// e.source.getActiveSheet().getRange(row,4).setValue(currentDate);
// if(e.source.getActiveSheet().getRange(row,3).getValue() == ""){
// e.source.getActiveSheet().getRange(row,3).setValue(currentDate)
// }
}
}
}
function onEdit(e) {
const sh = e.range.getSheet();
const row = sh.getRange(e.range.rowStart,1,1,sh.getLastColumn()).getDisplayValues()[0].join(',');//current row of active sheet
const name = e.source.getName();//spreadsheet name
//const name = sh.getName();//sheet name not sure which one you want
sendText('chatId', `${name)\n ${row}`);
}
You probably want to limit the trigger to a certain sheet and given row and column but I'll leave that up to you.

Placing a timestamp on a cell accross multiple sheets on edit

I tried many different variations of this script and can't figure out why it's not working.
I want to update the same cell "J3" with a timestamp across multiple tabs onedit. I have another function on the spreadsheet already using onEdit(e), so i set a new function with an onEdit trigger.
I retrieve the names of the tabs I want to update and store them in an array.
function Overview_timestamp(e) //function to use in the onEdit trigger
{
var activeSheet = e.source.getActiveSheet();
var range = e.range;
var cellToStamp = "J3" ;
var name_range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Structure').getRange(2, 5, 14, 1).getValues(); //sheets i want to update
var flattened_name_range = [] ; //converting into 1D array
for (var i = 0; i < name_range.length; i++) {
flattened_name_range.push(name_range[i][0]);
}
if(flattened_name_range.indexOf(activeSheet())!==-1 ) {
activeSheet.getRange(cellToStamp).setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm:ss");}
}
Try this:
function Overview_timestamp(e) {
const sh = e.range.getSheet();
if (sh.getName() == 'Sheet name') {//just to limit action to one sheet but it would be nice to have additional control like clicking a checkbox or selecting a value on a validated cell.
const shts = e.source.getSheetByName('Structure').getRange(2, 5, 14).getValues().flat();
shts.forEach(n => {
e.source.getSheetByName(n).getRange('J3').setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm:ss")
});
}
}
I did it this way on my sheet using a checkbox at A1 on Sheet1
function onEdit(e) {
//e.source.toast('entry');
const sh = e.range.getSheet();
if (sh.getName() == 'Sheet1' && e.range.columnStart==1 && e.range.rowStart==1 && e.value=='TRUE') {
//e.source.toast('cond');
const shts = e.source.getSheetByName('Sheet2').getRange(2, 5, 14).getValues().flat().filter(e=>e);
shts.forEach(n => {
e.source.getSheetByName(n).getRange('J3').setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm:ss")
});
e.range.setValue('FALSE');
}
}

Google Apps Script Not Loading Functions for Everyone, only me

My onSheetOpen / showSidebar is not working for anyone but me when opening my events Google sheet. I have set up triggers to launch both the onSheetOpen and showSidebar for myself, but this is not working for anyone else who opens the spreadsheet. Can anyone help figure out why this might be the case? Below is the code I'm using.
/**
* Set up custom sidebar.
* TRIGGER: spreadsheet event 'on open'
*/
function onSheetOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Actions')
.addItem("Register interest in current opportunity", 'registerInterest')
.addItem("Show sidebar", 'showSidebar')
.addToUi();
showSidebar();
}
/**
* Renders the sidebar
* TRIGGER: spreadsheet event 'on open' & custom menu option
*/
function showSidebar() {
try {
var htmlOutput = HtmlService.createHtmlOutputFromFile('sidebar');
SpreadsheetApp.getUi().showSidebar(htmlOutput);
} catch(e) {
// Just ignore - means user doesn't have edit access to sheet
}
}
/**
* Main function. Grabs the required data from the currently-selected row, registers interest
* in that data in a separate sheet, and sends a confirmation email to the user.
*/
function registerInterest() {
//var spreadsheet = SpreadsheetApp.getActive();
// These are the attributes we capture and store in the 'interest' sheet
var who = Session.getActiveUser().getEmail();
var when = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'yyyy-MM-dd HH:mm:ss');
var data = getRowOfInterest(SpreadsheetApp.getActiveSheet());
var id = Utilities.getUuid();
Logger.log(id)
if(data.what && data.what.length > 0) {
// Get the Google Sheets ID of the target 'interest' sheet
var id = getConfigValue("InterestSheet");
if(id) {
// Now try and open that sheet for updating
var ss = SpreadsheetApp.openById(id);
if(ss) {
var sheet = ss.getSheetByName('Interest');
if(sheet) {
// All good; log interest. First, create the new row of data for the target sheet
sheet.appendRow([ when, who, data.what, data.subject, data.location, data.industry, data.capabilities ]);
// Second, grab our 'template' email from config & use that to send a confirmation
// email to the person registering their interest
var body = getConfigValue('InterestEmail');
MailApp.sendEmail(who, getConfigValue('InterestSubject'), null, { noReply: true, htmlBody: body });
} else {
throw Error('can\'t open the \'Interest expressed\' sheet (or it doesn\'t exist)');
}
} else {
throw Error('can\'t open the \'Interest expressed\' sheet');
}
} else {
throw Error('\'Interest expressed\' sheet not specified');
}
}
}
/**
* Utility to derive the required data for registering interest.
* Called from the registerInterest() function
*/
function getRowOfInterest(sheet) {
var result = {};
var row = sheet.getActiveRange().getRow(); // Get the currently-selected row index
var fullRange = sheet.getRange(row, 1, 1, sheet.getLastColumn()); // Get the entire row of data
//var fullRange = sheet.getRange(row, 1, 1, 9);
Logger.log(fullRange.getValues())
var data = fullRange.getValues();
if(data[0] && data[0].length > 0) {
for(var n = 0; n < data[0].length; n++) {
// Populate specific attributes in the 'result' object - tailor this as you see fit
if(n==0) result.subject = data[0][n];
if(n==6) result.what = data[0][n] + ' ';
//if(n==5 || n==7) result.what += data[0][n] + ' ';
if(n==7) result.location = data[0][n];
if(n==11) result.industry = data[0][n];
if(n==12) result.capabilities = data[0][n];
}
result.what += '(' + sheet.getName() + ')';
result.industry;
result.capabilities;
return result;
}
}
function getSomeRange(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var row = sheet.getActiveRange().getRow(); // Get the currently-selected row index
var myRange = sheet.getRange(row, 1, 1, sheet.getLastColumn());
//Logger.log("Number of rows in range is "+myRange.getNumRows()+ " Number of columns in range is "+ myRange.getNumColumns());
}
/**
* Utility to pull specified data from a config sheet. This assumes that a sheet called 'Config'
* is populated thus:
* Column contains a load of 'key' and column 2 contains the corresponding 'values'
* Called from registerInterest() function
*/
function getConfigValue(key) {
var sheet = SpreadsheetApp.getActive().getSheetByName('Config');
var result;
if(sheet) {
// Scan column 1 for key and return value in column 2
var data = sheet.getDataRange().getValues();
for(var n = 0; n < data.length; ++n) {
if(data[n][0].toString().match(key)) result = data[n][1];
}
}
return result;
}
function hideExpiredEvents() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Events');
var exsh=ss.getSheetByName('Expired Events');
var sr=2;
var rg=sh.getRange(sr,1,sh.getLastRow()-sr+1,sh.getLastColumn());
var vA=rg.getValues();
Logger.log(vA);
var dt=new Date();
var d=0;//deleted row counter
var today=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate(0)).valueOf();
for(var i=0;i<vA.length;i++) {
if(new Date(vA[i][3]).valueOf()<today) {
exsh.appendRow(vA[i]);//move to bottom of expired events
sh.deleteRow(i+sr-d++);//increment deleted row counter
}
}
}
Unfortunately, it seems that the issue you are encountering might be a bug.
What you can do in this case is to star the issue on Issue Tracker here by clicking the ★ next to the issue number and post a comment as well saying that you are affected by the issue.

Google Sheets Script Missing Something

I'm creating a small database inside a sheet, I need the script to copy data to another sheet tab and I'm getting an empty error.
I'm not expert on javascript so what code I'm missing here?
Basically, when you press a button you get a text modal with an input so the person writes the name and then the script gets all the Rows with a TRUE (checkbox) and copies everything to another sheet with a header saying the data and time with the name of the person. If returns nulled with everything FALSE wont copy and shows a text modal saying that there's no task done today.
Thanks in advance
function moveValuesOnly() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange ("RESUMO!A4:J99");
var destSheet = ss.getSheetByName("LOG Resumo");
var row = destSheet.getLastRow()+2; //the starting column of the range
var column = 1; //the starting row of the range
var numRows = 97; //the number of rows to return
var numColumns = 10; //the number of columns to return
var destRange = destSheet.getRange(row, column, numRows, numColumns);
var input_text = Browser.inputBox("Encarregado de Turno","Escreve seu nome:", Browser.Buttons.OK);
var now = new Date();
var active = ss.getSheetByName("RESUMO");
var condition = active.getRange('RESUMO!J4:J99').getValue();
var valueToWatch = "TRUE";
if (condition == valueToWatch) {
destSheet.getRange(row-1,1,1,10).mergeAcross().setBackgroundRGB(224, 102, 102).setFontColor("white");
destSheet.getRange(row-1,1,1).setValue(now + " ~~ ENCARREGADO DE FECHAR TURNO: " + input_text).activate();
source.copyTo(destRange, {contentsOnly: true}).setFontColor("black");
} else {
Browser.msgBox("Erro","Não exite tarefas completas hoje", Browser.Buttons.OK);
}
}
There are following issue with your code:
If you have TRUE and FALSE values as cell contents, Spreadsheets will automatically identify them as booleans, rather than strings. Thus, also valueToWatch needs to be a boolean rather than a string: var valueToWatch = true;
If you want to verify the "TRUE" condition for each row - you need to do it in a loop. Consequently, you code needs to be modified a bit. One way to do so is to push all rows where the cell content in column J is TRUE into an array and then pass the contents of this array to a destination range with the same dimension as the array. This is what the resulting code would look like:
function moveValuesOnly() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange ("RESUMO!A4:J99");
var destSheet = ss.getSheetByName("LOG Resumo");
var row = destSheet.getLastRow()+2; //the starting column of the range
var column = 1; //the starting row of the range
var input_text = Browser.inputBox("Encarregado de Turno","Escreve seu nome:", Browser.Buttons.OK);
var now = new Date();
var active = ss.getSheetByName("RESUMO");
var condition = active.getRange('RESUMO!J4:J99').getValues();
destSheet.getRange(row-1,1,1,10).mergeAcross().setBackgroundRGB(224, 102, 102).setFontColor("white");
destSheet.getRange(row-1,1,1).setValue(now + " ~~ ENCARREGADO DE FECHAR TURNO: " + input_text).activate();
var valueToWatch = true;
var values=source.getValues();
var array=[];
for(var i=0;i<condition.length;i++){
if (condition[i][0] == valueToWatch) {
array.push( values[i]);
}
}
if(!array) {
Browser.msgBox("Erro","Não exite tarefas completas hoje", Browser.Buttons.OK);
}
else {
var numRows = array.length; //the number of rows to return
var numColumns = array[0].length; //the number of columns to return
var destRange = destSheet.getRange(row, column,numRows , numColumns);
destRange.setValues(array).setFontColor("black");
}
}

"The coordinates of the target range are outside the dimensions of the sheet" error when looping [duplicate]

This question already has an answer here:
Copying data script is not working anymore
(1 answer)
Closed last month.
I have 4 sheets. Form, Raw, URL and USA/Japan/Canada. I get the spreadsheet url value from the URL sheet and use 'IMPORTRANGE' in the Raw sheet to transfer the data table. From there, i loop through the table in Raw sheet to check if the values is match from the values in the Form sheet. If it's matched, i will transfer that row in the USA/Japan/Canada sheet.
So i got this code in my google sheets:
var mainWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form');
var continentWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('USA/Japan/Canada');
var rawWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Raw');
var urlWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('URLs');
var tourName = mainWS.getRange('C4').getValue();
var depDate = new Date(mainWS.getRange('C5').getValue());
var status = mainWS.getRange('C6').getValue();
//extract table data
var url = urlWS.getRange("B4").getValue();
rawWS.getRange('A1').setValue('=IMPORTRANGE("' + url + '","Main Data!A1:AE")');
var dummyHolder = rawWS.getRange("B1:B").getValues();
var lastRow = dummyHolder.filter(String).length;
Logger.log(lastRow);
//loop through the raw extract
for(var i = 2; i <= lastRow; i++){
var dateHolder = new Date(rawWS.getRange("E" + i).getValue());
if(rawWS.getRange("F" + i).getValue() == tourName && rawWS.getRange("I" + i).getValue() == status && dateHolder.getTime() === depDate.getTime()){
var continentLR = continentWS.getLastRow() + 1;
rawWS.getRange('Raw!' + i + ':' + i + '').copyTo(continentWS.getRange(continentLR, 1), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
}
}
Then i suddenly get the "The coordinates of the target range are outside the dimensions of the sheet" error message once it enters the loop. Specifically in the first line after the for loop:
var dateHolder = new Date(rawWS.getRange("E" + i).getValue());
To be clear, the rawWS where it is looping has 134 records and it registers 134 as its last row. I don't know why i am getting an error here.
When i remove that line, it still gives me an error on the next line. It all errors inside the for loop.
Any ideas?
I haven't tested this but give it a try:
I think that the problem with filter is that it will remove blanks before the end as well but getValues() won't. So you can end up with the wrong length depending upon the dataset.
function unknown() {
var formWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form');
var continentWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('USA/Japan/Canada');
var rawWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Raw');
var urlWS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('URLs');
var tourName = formWS.getRange('C4').getValue();
var depDate = new Date(formWS.getRange('C5').getValue());
var status = formWS.getRange('C6').getValue();
//extract table data
var url = urlWS.getRange("B4").getValue();
rawWS.getRange('A1').setValue('=IMPORTRANGE("' + url + '","Main Data!A1:AE")');
var dummyHolder = rawWS.getRange(1,2,rawWS.getLastRow(),1).getValues();
for(var i=dummyHolder.length-1;i>=0;i--){
if(!dummyHolder[i][0]){
dummyHolder.splice(i,1);
}else{
break;
}
}
//loop through the raw extract
for(var i=2;i<dummyHolder.length; i++){
var dateHolder = new Date(rawWS.getRange(i,5).getValue());
if(rawWS.getRange(i,6).getValue() == tourName && rawWS.getRange(i,9).getValue() == status && dateHolder.getTime() === depDate.getTime()){
var continentLR = continentWS.getLastRow() + 1;
rawWS.getRange(i,1,).copyTo(continentWS.getRange(continentLR, 1), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
}
}
}
Array Filter Method
Also your last line included sheet name in the range but rawWS is that sheet. So I rewrote the range parameters. Sorry if this doesn't work.

Categories