When do values get written to a Google Sheet cell? - google-apps-script

I'm experiencing a weird issue. When I type text in a Google Sheet cell, then run a custom script (below) to get those values, it doesn't get the values I just type in. The values only become available once I move away from that cell (tab or enter).
var data = dataRange.getValues();
I'm not sure when the values actually get written to the cell. If I script a move away from that cell (below), I get the same issue.
var newRange = sheet.getRange("C4");
sheet.setCurrentCell(newRange);
Is there a way to write all the data to the sheet?
Can test using this code. Write some text to A1, run custom script and check the logs. If you don't move away from A1 before running script, logs will be empty.
function moveTest(){
var sheet = SpreadsheetApp.getActiveSheet();
var newRange = sheet.getRange("A2");
sheet.setCurrentCell(newRange);
var cellOfInterest = sheet.getRange("A1").getValue();
Logger.log(cellOfInterest);
}
Edit: same issue with setActiveSelection instead of setCurrentCell

When do values get written to a Google Sheet cell?
When you press tab, arrow keys, enter or any other method that takes the focus away from the cell, the value gets written or committed.

I'm not sure if it would work for you, but if you are checking for 1 exact cell, an if statement checking if the input is recognized before running the script would be alright:
function checkwritten(){
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var ui = SpreadsheetApp.getUi();
var InterestCell = sheet.getRange("A1");
var cellOfInterest = sheet.getRange("A1").getValue();
if (InterestCell.isBlank()) {
Logger.log("missing value");
ui.alert('There are missing values');
}
else {
Logger.log(cellOfInterest);
/*
enter code here
*/
}
}
The other solutions proposed, such as making the button a menu option, or greying out the button until all entry is filled is also viable.
If you are checking for a range, the following two options are viable:
Option 1: create a cell with countblank in your sheet and it would be the cell of interest.
function checkwritten(){
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var InterestCell = sheet.getRange("A6");
var cellOfInterest = sheet.getRange("A6").getValue();
if (cellOfInterest == 0) {
Logger.log("success");
}
else {
Logger.log(cellOfInterest);
/*
enter code here
*/
}
}
Option 2 - allow the script to ensure that there is no blank cells before running.
function checkwritten(){
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var CellCheckCount = 100; // 1 above the total number of rows to check
var ui = SpreadsheetApp.getUi();
var BlankCellCount = 0;
var CheckCell = null;
for (var i = 1; i < CellCheckCount; i++){
CheckCell = sheet.getRange(i,1); //currently set to check column 1 up till 100-1 row
if (CheckCell.isBlank()){
BlankCellCount++;
}
else{
}
}
if (BlankCellCount == 0) {
Logger.log("success");
/*
enter code here
*/
}
else {
Logger.log("fail" + BlankCellCount);
}
}

Related

How to refresh a filter onEdit() in Google sheets?

I have a sheet where I fill data with Hlookups depending on the values I choose in dropdowns.
I want to filter (hide) the rows that have a NULL or blank value in column 3 each time I change the values in the dropdowns (which changes the whole dataset).
If I create a normal filter, it doesn't refresh when the data changes.
var PARAMETER_ROW_NUMBER = 5; //The parameters goes from Row 1 to this Row
var PARAMETER_COLUMN_NUMBER = 2; //The column where the dropdowns with the parameters for the VLOOKUPs are
function onEdit()
{
var thisSheet = SpreadsheetApp.getActiveSheet();
if( thisSheet.getName() == "By Place" )
{
var cell = thisSheet.getActiveCell();
var cellRow = cell.getRow();
var cellColumn = cell.getColumn();
if( cellColumn == PARAMETER_COLUMN_NUMBER && cellRow <= PARAMETER_ROW_NUMBER)
{
setFilter(); // Execute the filter to clean null rows each time I change the values in the dropdowns
var rowDiff = PARAMETER_ROW_NUMBER - cellRow;
cell.offset( 1, 0, rowDiff).setValue(''); // As the parameters are dependent dropdowns, I clear the dropdowns if one changes
}
}
}
function setFilter()
{
var ss = SpreadsheetApp.getActiveSheet();
var rang = ss.getDataRange();
var filtercriteria = SpreadsheetApp.newFilterCriteria().setHiddenValues([' ','']).build();
var filter = rang.getFilter() || rang.createFilter();
filter.setColumnFilterCriteria(3, filtercriteria); // I want to hide the rows which has a null or blank in column 3
}
The setFilter() function doesn't work.
The array you're using to set the hidden values is not correct, try your code like this:
function setFilter()
{
var ss = SpreadsheetApp.getActiveSheet();
var rang = ss.getDataRange();
var filterCriteria = SpreadsheetApp
.newFilterCriteria()
.setHiddenValues(['NULL', ''])
.build();
var filter = rang.getFilter() || rang.createFilter();
filter.setColumnFilterCriteria(3, filterCriteria);
}
Also, if you want to see the logs from your onEdit executions, you can check them on your Apps Script file by clicking in View - > Executions, there you will be able to see the errors you are getting.
Docs
I used these docs to help you:
setColumnFilterCriteria(columnPosition, filterCriteria).
Class FilterCriteriaBuilder.

getValues and getBackgrouds not returning data in Google Apps Script

I'm trying to create a code that checks to see if a cell has a checkbox checked (or unchecked) and then copies data from a corresponding cell on that row onto another "Summary" sheet. The "if checked then copy data" portion has not been included below.
The problem I'm having is that neither getValues nor getBackgound seems to be returning data.
When I run my code, the Logger shows that every checkbox value is "false" (even though some are checked and I have their values set to 1 (checked) and 0 (unchecked) using the data validation in the spreadsheet settings.
If I switch to getBackgrounds, the Logger shows that every cell's background is white "#ffffff", even though the cells are red.
[[I want my code to iterate over every sheet, row, and column. It seems to be iterating fine, but not retrieving the data.]]
What I am doing wrong? Here's my full code:
function MAPSuccess() {
var app = SpreadsheetApp;
var ss = SpreadsheetApp.openByUrl(
'https://docs.google.com/spreadsheets/d/1UUdiLsz2OvKdqnr2KB0Tx74gzrGx0m4XUA5oNMUB06k/edit');
var allsheets = ss.getSheets();
var s = ss.getNumSheets();
var master = app.getActiveSpreadsheet().getSheetByName("Master");
var masterLastRow = master.getLastRow();
for (var s = 2; s < allsheets.length; s++) {
var sheet = app.getActiveSpreadsheet().getActiveSheet();
var r = sheet.getCurrentCell().getRow();
var lastrow = sheet.getLastRow();
var lastcol = sheet.getLastColumn();
var temail = sheet.getRange(1,2);
var tSJCOE = sheet.getRange(2,2);
var c = sheet.getActiveCell().getColumn();
for(var r = 4;r<=lastrow;r++){
var name= sheet.getRange(r,1).getValue();
var lname= sheet.getRange(r,2).getValue();
var email= sheet.getRange(r,3).getValue();
var pemail= sheet.getRange(r,4).getValue();
var info = [
[name, lname, email, pemail]
]
var range = sheet.getRange(r,1,1,lastcol);
var rowValues = range.getValues();
var cell = [
[s,r,c]
];
Logger.log(rowValues);
Logger.log(name);
// Logger.log(checkRow);
Logger.log(cell);
It looks like you are always performing your actions on the active sheet, instead of accessing the sheets in "allsheets".
var sheet = app.getActiveSpreadsheet().getActiveSheet();
should be
var sheet = allsheets[s];
You may also be misusing "getCurrentCell" on the next line, since that will return whichever cell is currently selected in the spreadsheet, of which there is always only one, regardless of which sheet you are accessing.

google sheets script conditionally move row to another spreadsheet

I am new to this and I am having some trouble trying to figure this out. I have a spreadsheet that collects data from a google form. I am trying to find a way to move that data based on a column answer to a different google sheet. (Not a sheet in the same document but a different document all together). It seems like there is some information about moving to a different tab in the same document, but not a different document.
I will first say that I tried just an IMPORTRANGE function, but that only mirrors the data, and does not let you update or change cells.
Here is what I have been able to piece together so far, but I may be way off.
I have a trigger that would run every hour.
function myFunction() {
var ss = SpreadsheetApp.openById('1U0I9SkbGkHgm-vRkwf2Ppc_yxlqrVlg2t8yKRy3sYuI');
var sheetOrg = ss.getSheetByName("Form Responses 1");
var value1ToWatch = "ANDERSON";
var value2ToWatch = "BARNES";
var sheetNameToMoveTheRowTo = "Sheet1"; //sheet has same name for each target openByID(" *url key* ")
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ts1 =SpreadsheetApp.openById("1PxV1PQrMdu_2aSru4dpan8cUgHYdlYPUp5anyzjMAms");
sheet1in = ts1.getSheetByName("Sheet1");
var ts2 = SpreadsheetApp.openById("1BYyQZNiXc2QqsyqWs7uazjl5B6mfFYM1xj3u8gWyYOQ");
sheet1in = ts2.getSheetByName("Sheet1");
arr = [],
values = sheetOrg.getDataRange().getValues(),
i = values.length;
while (--i) {
if (value1ToWatch.indexOf(values[i][1]) > -1) {
arr.unshift(values[i])
sheetOrg.deleteRow(i + 1)
sheet1in.getRange(sheet1in.getLastRow()+1, 1, arr.length,
arr[0].length).setValues(arr);
};
if (value2ToWatch.indexOf(values[i][1]) > -1) {
arr.unshift(values[i])
sheetOrg.deleteRow(i + 1)
sheet2in.getRange(sheet2in.getLastRow()+1, 1, arr.length,
arr[0].length).setValues(arr);
};
}
}
The sheet google forms dumps the information into is "Form Responses 1".
Column B is the cells I want to get the values from. (There are a total of 9 different values that it can be like "ANDERSON", "BARNES", "SMITH", etc).
For sheetNameToMoveTheRowTo is "Sheet1" - that may be confusing and I may need to change that, but for example
ts1 =SpreadsheetApp.openById("1PxV1PQrMdu_2aSru4dpan8cUgHYdlYPUp5anyzjMAms") the sheet name that I want the information moved to is "Sheet1".
ts2 = SpreadsheetApp.openById("1BYyQZNiXc2QqsyqWs7uazjl5B6mfFYM1xj3u8gWyYOQ") the sheet name is also "Sheet1" but in a different document.
I think if I were able to get the "ANDERSON" one to work, then I can just add additional variables for each possible response, and just copy and paste additional "IF" statements, just changing the valueToWatch and targetSheet values. <= if that is not correct please let me know
I have tried to both debug, and run the script above but nothing happens. There are no errors reported on the debug, but it is not moving any information over.
Any idea what I am doing wrong?
// UPDATE I got this to work. I have updated the code listed with what worked for me.
I think that copyTo() method will not work like you mentioned, it operates on same SpreadSheet. I'm sending you example with looping on source sheet data and then setting the target sheet values with it.
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var allrange = ss.getActiveRange();
var range = sheet.getRange("A1:A10");
var values = range.getValues();
var allvals = [];
for(var i = 0; i < values.length; i++) {
allvals.push( values[i] ) ;
}
var dataLength = allvals.length;
// alert data
var ui = SpreadsheetApp.getUi();
// ui.alert( JSON.stringify(allvals) )
// copy to new Google SpreadSheet
var newSheet = SpreadsheetApp.openById('1F79XkNPWm2cCWlB2JP3K4tAYRESKUgtHK4Pn2vbJEiI').getSheets()[0];
var tmp = "A1:A" + dataLength ;
var newRange = newSheet.getRange( tmp );
newRange.setValues( allvals );
}
Here's a simple example of moving data from one spreadsheet to another.
function movingDataToSS(){
var ss=SpreadsheetApp.getActive();
var dss=SpreadsheetApp.openById('ssId');
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var dsh=dss.getSheetByName('Sheet1');
var drg=dsh.getRange(1,1,rg.getHeight(),rg.getWidth()).setValues(vA);
}
If you interested in placing some conditions on your output by only getting output from odd rows and even columns.
function movingDataOddRowsAndEvenCols(){
var ss=SpreadsheetApp.getActive();
var dss=SpreadsheetApp.openById('ssId');
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var h=rg.getHeight();
var w=rg.getWidth();
var dsh=dss.getSheetByName('Sheet1');
for(var i=0;i<h;i++){
var out=[];
if(i%2==0){
for(var j=0;j<w;j++){
if(j%2==1){
out.push(vA[i][j]);
}
}
dsh.appendRow(out);
}
}
}

Cursor automatically moved to Cell A1 in google spreadsheet with app script after each edit

I have generated the following codes in app script in order to send emails automatically if users changed some values in google spreadsheet.
Then I connected my script to the google spreadsheet by changing "current project's trigger". e.g:
my trigger.jpg
The code is working fine. The only problem is that after users insert/edit new values in any cells (e.g: B1, B12, C12,etc) in google spreadsheet, it is going to trigger my scripts, and then the cursor will always be automatically moved to cell A1, which is annoying.
My best guess (which I could be wrong) is that it goes back to cell A1 as a "signal" as it finishes running the app script codes every time?
Is there anything I could do to stop this automatic cursor moving thing? Do I need to change the "current project's trigger"?
function PODTool() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
var sheet = spreadsheet.getActiveSheet();
var lastRow = sheet.getLastRow();
var startRow = 2;
var range = sheet.getRange(2,7,lastRow-startRow+1,1 );
var numRows = range.getNumRows();
var LinksToPODForm = range.getValues();
var rangeColumnReadyToSendEmail =sheet.getRange(2,9,lastRow-startRow+1,1);
var sendEmailOrNot = rangeColumnReadyToSendEmail.getValues();
var warning_count = 0;
var msg = "";
// Loop over the values
for (var i = 0; i <= numRows - 1; i++) {
var EachLinkValue = LinksToPODForm[i][0];
if (EachSendEmailOrNotValue=="yes" && sheet.getRange(i+2,10).getValue()=='Email not Sent' &&EachEmailRecipient=="Someone"){
var BillingOfLadingShowingInEmailNotification = Billing_of_lading_number[i][0];
msg = msg +"Requester: "+EachEmailRecipient+"
warning_count++;
var subject ="Billing of Lading: "+BillingOfLadingShowingInEmailNotification;
sheet.getRange(i+2,10).setValue('Sent');
var recipient = "xxx#gmail.com";
}
if(warning_count) {
MailApp.sendEmail(recipient, subject,msg)
}
};
Thx for any advice!!
I would change this:
var sheet = spreadsheet.getActiveSheet();
to:
var sheet = spreadsheet.getSheets()[0];
and delete this line:
SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);

How to set trigger 'onOpen' on a spreadsheet instead of a sheet? (Focus last row)

I want to focus the last row on a specific sheet (or if possible on every one of them) so here is my function triggered by onOpen on the sheet:
function FocusLastRows() {
var spsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spsheet.getSheetByName("Usuelle_2013");
var rowInt = sheet.getLastRow();
var colInt = sheet.getLastColumn();
var range = sheet.getRange(rowInt, colInt)
sheet.setActiveRange(range)
}
This event works but if my first loaded sheet is different from the one I want it to focus on it just teleports to the other sheet. Best will be to set an .onOpen on the spreadsheet.
Is that possible?
I found a good alternative for it. It's custom menu with function link to it.
//Pierre-luc Des. Script
//Build your menu
function setMenu() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menubuttons = [ {name: "Dernière ligne usuelle", functionName: "GOTOLastRow}];
ss.addMenu("Outils", menubuttons);
}
function GOTOLastRow() {
var spsheet = SpreadsheetApp.getActiveSpreadsheet();
var currentTime = new Date();
var sheet = spsheet.getSheetByName("Usuelle_" + currentTime.getFullYear());
var rowInt = sheet.getLastRow();
var colInt = sheet.getLastColumn();
var range = sheet.getRange(rowInt, colInt);
sheet.setActiveRange(range);
}
Now i will have a clickable menu "Outils" which will let me do the function.
This is rather inelegant, but perhaps try just checking whether the activated sheet is the target sheet? Something like this:
function FocusLastRows() {
var spsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spsheet.getSheetByName("Usuelle_2013");
if (sheet == spsheet) {
var rowInt = sheet.getLastRow();
var colInt = sheet.getLastColumn();
var range = sheet.getRange(rowInt, colInt);
sheet.setActiveRange(range);
}
}
The Google Apps Script documentation seems to indicate that you'll need custom libraries to get any other trigger events than the ones provided, and I'm not sure if it's even in-principle possible to trigger only when a certain specific sheet is activated.
I figure checking the sheet with if comparisons is the next-simplest solution.