GetCell -> GetValue -> SetValue fails - google-apps-script

I want to make the below mentioned code working but it doesn't - nothing happens when I run it (also no error), that means the username (sUserName) doesn't get saved in the spreadsheet... And also I don't understand why the columns cant start with 2, 3, 4 (then the timestamp can stay in column #1) instead 1, 2, 3 - if so I get an error.
Here is the code:
var userNameColumn = 1; //Column where the user name is written
var subTypeColumn = 2; //Column where the submitter type is written ex. "Requester"
var sUserNameColumn = 3; //Column where the user name is saved
function saveUserName() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
for (var i = 1; i <= numRows; i++) {
var userNameCell = rows.getCell(i, userNameColumn);
var subTypeCell = rows.getCell(i, subTypeColumn);
var sUserNameCell = rows.getCell(i, sUserNameColumn);
if(sUserNameCell.isBlank() && subTypeCell.getValue() === 'Requester') {
sUserNameCell.setValue(userNameCell)
};
}
}
Here is the link for my spreadsheet and code:
Google Spreadsheet

See if this helps
function saveUserName() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var rows = sheet.getDataRange().getValues();
for (var i = 1; i < rows.length; i++) {
var userNameCell = rows[i][1];
var subTypeCell = rows[i][2];
var sUserNameCell = rows[i][3];
if (!sUserNameCell && subTypeCell === 'Requester') sheet.getRange(i+1,4).setValue(userNameCell)
}
}

Related

How to loop through cells in Google Sheets and log information if specific variables exist

You will need this link to solve this: - https://docs.google.com/spreadsheets/d/11PjVSWPfqOBPSej3AlQ-_T8Bws66kevR08Q2NRTmVcE/edit?usp=sharing
So this is a tricky one. I am looking to loop through the name in Sheet1 Column A, and also loop through the type in Column C. Then if Column A in Sheet1 matches the name of column A in Sheet2, AND the type is "pickup" I want to log the other information that is in Sheet 1 inside of Column C on Sheet 2. Log the things like "State", "Location", "City" next to the identical name in Sheet 2. I hope that makes sense.
I know I probably need to use a loop within a loop to do all this, but this is as far as I can get as I cannot figure out how to write the loop and then log the rows where the 2 names match.
function myFunction() {
function pullDeliveryNotes()
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var dataRange = sheet.getDataRange();
var dataRange2 = sheet2.getDataRange();
var rng = sheet.getRange(2,1, dataRange.getLastRow()-1,dataRange.getLastColumn());
var rng2 = sheet.getRange(2,3, dataRange.getLastRow()-1,dataRange.getLastColumn());
var rng3 = sheet2.getRange(2,1, dataRange2.getLastRow()-1,dataRange2.getLastColumn());
var rngA = rng.getValues().toString()
var rngB = rng2.getValues().toString()
var rngC = rng3.getValues().toString()
for(var i = 0; i < rng.length; i++) {
for (var x = 0; x < rng2.length; x++) {
for (var y = 0; y < rng3.length; y++) {
if (rng[i][x][y].includes(rng3[i][x][y]) && rng2[i][x][y] === "pickUp") {
Logger.log("We got it")
}
}
}
}
}
}
Based on your problem statement.
Try this sample script:-
function checkValues() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ssSource = ss.getSheetByName('Sheet1')
const ssTarget = ss.getSheetByName('Sheet2')
const sourceRange = ssSource.getDataRange().getValues().filter(r=> r[2] === 'Pickup'); // Filtering only pickup values
const targetRange = ssTarget.getDataRange().getValues();
for(var i = 0 ; i < sourceRange.length ; i++)
{
for(var j = 1 ; j < targetRange.length ; j++)
{
if(sourceRange[i][0] === targetRange[j][0]) // if name matches
{
ssTarget.getRange(`C${j+1}`).setValue(`${sourceRange[i][3]},${sourceRange[i][4]},${sourceRange[i][5]}`) // set values in column C
}
}
}
}

Capture values and send email trigger

I managed to collect data of user typing in and by using onChange trigger, I did meet my requirements for my task. However, I realized that for example I am filling up Column A1:A4. If my A1:A3 is out of range, it will trigger the email. But if my A4 is within range, the values of A1:A3 will still trigger the email eventhough it has trigger it before. How do I make sure that the values that have been capture do not trigger the email again?
function myFunction() {
var ss = SpreadsheetApp.getActiveSheet();
currentsheet = ss.getSheetName();
//var values = ss.getRange(a1Notation)
//console.log(values);
var lastcol = ss.getLastColumn();
var vibrationtemplate = HtmlService.createTemplateFromFile("vibration");
var temperaturetemplate = HtmlService.createTemplateFromFile("temperature");
//console.log(lastcol);
if((currentsheet == 'A Vibration') || (currentsheet == 'B Vibration')){
console.log(currentsheet);
for(var i =2; i<=lastcol; i++){
var cell = ss.getRange(i,lastcol).getValues();
console.log(""+cell);
if(cell > 8){
console.log("Value is more than 8 and current value is "+cell);
vibrationtemplate.vibrate = cell;
MailApp.sendEmail("someone#gmail.com",
"Parameter Out of Range Notification",
"",{htmlBody: vibrationtemplate.evaluate().getContent()});
}
}
}
if((currentsheet == 'A Temperature') || (currentsheet == 'B Temperature')){
console.log(currentsheet);
for(var i =2; i<=lastcol; i++){
var cell = ss.getRange(i,lastcol).getValues();
console.log(""+cell);
if(cell > 80){
console.log("Value is more than 80 and current value is "+cell);
temperaturetemplate.temp = cell;
MailApp.sendEmail("someone#gmail.com",
"Parameter Out of Range Notification",
"",{htmlBody: temperaturetemplate.evaluate().getContent()});
}
}
}
}
EDIT: Latest code - Using a daily trigger and only checks at the end of the day.
function myFunction() {
const ss = SpreadsheetApp.getActiveSheet();
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var sheetNumber = sheets.length; //Get number of sheets within Spreadsheet
var currentSheet = ss.getIndex()-1; //Get index of current sheet with 0 indexing
var vibrationtemplate = HtmlService.createTemplateFromFile("vibration"); //Create HTML for email by grabbing template from vibration.html
var temperaturetemplate = HtmlService.createTemplateFromFile("temperature"); //Create HTML for email by grabbing template from temperature.html
const vibrationlimit = 8; //Set vibrationlimit as constant equals to 8
const temperaturelimit = 80; //Set temperaturelimit as constant equals to 80
var currentDate = new Date(); //Get system Date and Time
var currentDay = currentDate.getDate(); //Extract Date from Full Date(currentDate)
var currentMonth = currentDate.getMonth() +1; //Extract Month from Full Date(currentDate), add +1 as month index start from 0.
for (var z = currentSheet ; z<sheetNumber ; ++z ){
SpreadsheetApp.setActiveSheet(sheets[z])
var lastcol = sheets[z].getLastColumn();
var lastrow= sheets[z].getLastRow();
var cellDate = sheets[z].getRange(1,lastcol).getValues();
var formattedCellDate = new Date(cellDate);
var cellDay = formattedCellDate.getDate();
var cellMonth = formattedCellDate.getMonth() + 1;
if((z==0) || (z==2)){
if((cellDay == currentDay) && (cellMonth == currentMonth)){
for(var i = 2; i<=lastrow; i++){
var scxvibrationname = sheets[z].getRange(i,1).getValues();
var vibration = sheets[z].getRange(i,lastcol).getValues();
if(vibration > vibrationlimit){
Logger.log("Vibration over 8 - Current Value is "+vibration);
vibrationtemplate.vibrate = vibration;
vibrationtemplate.scxvibration = scxvibrationname;
}
}
}
}
}
You can use PropertiesService to store the last row of the previous script run
The following code sets the start row for the for loop to the (last row+1) of the previous script run, so that only e-mails from newly added rows will be sent:
function myFunction() {
var ss = SpreadsheetApp.getActiveSheet();
currentsheet = ss.getSheetName();
//var values = ss.getRange(a1Notation)
//console.log(values);
var lastcol = ss.getLastColumn();
var lastrow=ss.getLastRow();
var vibrationtemplate = HtmlService.createTemplateFromFile("vibration");
var temperaturetemplate = HtmlService.createTemplateFromFile("temperature");
//console.log(lastcol);
if(PropertiesService.getScriptProperties().getKeys().length==0){
PropertiesService.getScriptProperties().setProperty('startRow', lastrow+1);
}
var startRow=PropertiesService.getScriptProperties().getProperty('startRow');
if((currentsheet == 'A Vibration') || (currentsheet == 'B Vibration')){
console.log(currentsheet);
//I ASSUME THAT YOU WANT TO LOOP THROUGH ALL ROWS AND NOT COLUMNS
for(var i =startRow; i<=lastrow; i++){
var cell = ss.getRange(i,lastcol).getValues();
console.log(""+cell);
if(cell > 8){
console.log("Value is more than 8 and current value is "+cell);
vibrationtemplate.vibrate = cell;
MailApp.sendEmail("someone#gmail.com",
"Parameter Out of Range Notification",
"",{htmlBody: vibrationtemplate.evaluate().getContent()});
}
}
}
...
PropertiesService.getScriptProperties().setProperty('startRow', lastrow+1);
}
function myFunction() {
const ss = SpreadsheetApp.getActiveSheet();
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var sheetNumber = sheets.length; //Get number of sheets within Spreadsheet
var currentSheet = ss.getIndex()-1; //Get index of current sheet with 0 indexing
var vibrationtemplate = HtmlService.createTemplateFromFile("vibration"); //Create HTML for email by grabbing template from vibration.html
var temperaturetemplate = HtmlService.createTemplateFromFile("temperature"); //Create HTML for email by grabbing template from temperature.html
const vibrationlimit = 8; //Set vibrationlimit as constant equals to 8
const temperaturelimit = 80; //Set temperaturelimit as constant equals to 80
var currentDate = new Date(); //Get system Date and Time
var currentDay = currentDate.getDate(); //Extract Date from Full Date(currentDate)
var currentMonth = currentDate.getMonth() +1; //Extract Month from Full Date(currentDate), add +1 as month index start from 0.
for (var z = currentSheet ; z<sheetNumber ; ++z ){
SpreadsheetApp.setActiveSheet(sheets[z])
var lastcol = sheets[z].getLastColumn();
var lastrow= sheets[z].getLastRow();
var cellDate = sheets[z].getRange(1,lastcol).getValues();
var formattedCellDate = new Date(cellDate);
var cellDay = formattedCellDate.getDate();
var cellMonth = formattedCellDate.getMonth() + 1;
if((z==0) || (z==2)){
if((cellDay == currentDay) && (cellMonth == currentMonth)){
for(var i = 2; i<=lastrow; i++){
var scxvibrationname = sheets[z].getRange(i,1).getValues();
var vibration = sheets[z].getRange(i,lastcol).getValues();
if(vibration > vibrationlimit){
Logger.log("Vibration over 8 - Current Value is "+vibration);
vibrationtemplate.vibrate = vibration;
vibrationtemplate.scxvibration = scxvibrationname;
}
}
}
}
}
I manipulated by using daily time-driven trigger.

Script exceeds maximum execution time

I am using a script to first copy a list of all terminated products from "data" tab of the sheet to the "terminated tab"
The data tab looks like below
The code checks if there is an end date written
if it is - the row is copied and pasted in the "terminated" tab
Once all rows (around 2000) are completed
the code the deletes all rows from the "data" tab that have an end date on it
But the code is not very efficient and data is huge - I get a "maximum execution time exceeded" error
function movingTerms() {
var app = SpreadsheetApp ;
var sheet1 = app.getActiveSpreadsheet().getSheetByName("data") ;
var sheet3 = app.getActiveSpreadsheet().getSheetByName("Terminations");
var range1 = sheet1.getRange(2, 1, sheet1.getLastRow() - 1,9);
var range3 = sheet3.getRange(2, 1, sheet3.getLastRow(), 9);
var values1 = range1.getValues();
var values3 = range3.getValues();
var rowcount = sheet1.getLastRow();
var row_deleted = 0;
for (var i = 0; i < (sheet1.getLastRow() - 1); i++)
{
if (values1[i][4] !== "")
{
var rowtodelete = sheet1.getRange(i + 2, 1, 1, 10);
var rowtoadd = sheet3.getRange(sheet3.getLastRow() + 1, 1);
rowtodelete.copyTo(rowtoadd);
}
}
for (var k = 0; k < values1.length; k++)
{
var row = k + 1 - row_deleted;
if (values1[k][4] !== "")
{
var getridof = row +1;
sheet1.deleteRow(getridof);
row_deleted++;
}
}
}
I generally like to see the spreadsheet to do this correctly but this is the way that I would do it.
function movingTerms() {
var ss=SpreadsheetApp.getActive();
var sheet1=ss.getSheetByName("data") ;
var sheet3=ss.getSheetByName("Terminations");
var range1=sheet1.getRange(2, 1, sheet1.getLastRow()-1,9);
var range3=sheet3.getRange(2, 1, sheet3.getLastRow(),9);//You don't really need this
var values1=range1.getValues();
var values3=range3.getValues();//You don't really need this
var rowcount=sheet1.getLastRow();
var rowsdeleted = 0;
for (var i=0;i<values1.length;i++) {
if (values1[i][4]!="") {//column5
var rowtodelete = sheet1.getRange(i-rowsdeleted+2, 1, 1, 10);
var rowtoadd = sheet3.getRange(sheet3.getLastRow()+1,1);//You could also append to sheet 3 if you wish
rowtodelete.copyTo(rowtoadd);
sheet1.deleteRow(i-rowsdeleted+2);
rowsdeleted++;
}
}
}

Google Apps Script mysteriously stops functioning in for loop

I am building a system to copy data from one sheet to another sheet (On a different spreadsheet). It works well, until it is supposed to copy the data. Afterward, it does nothing. No error is thrown, but no alert boxes pop up in the for loop. Here is my code:
function onEdit() {
var sheet = SpreadsheetApp.getActiveSheet();
var master = SpreadsheetApp.openById('13x7AvyYTaocCVBxVZ3ckBjzgxcZfjg9RYM1cE_0VNbU');
var sheets = master.getSheets();
var test = DriveApp.createFile('Test', 'fetching user data...');
var name = test.getOwner().getName();
test.setTrashed(true);
var add = true;
for (var i = 0, n; i < sheets.length; i++) {
n = sheets[i];
if (n.getName() == name) {
add = false;
updateSheet(n, name);
}
}
if (add) {
newSheet(master, name);
}
}
function updateSheet(m, name) {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());
var nr = range.getNumRows();
var nc = range.getNumColumns();
for (var i = 1; i <= nr.length; i++) {
for (var n = 1, s; n <= nc.length; n++) {
s = range.getCell(i, n);
m.getRange(i, n).getCell(1, 1).setValue(s.getValue());
}
}
}
function newSheet(master, name) {
var m = master.insertSheet(name);
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());
var nr = range.getNumRows();
var nc = range.getNumColumns();
for (var i = 1; i <= nr.length; i++) {
for (var n = 1, s; n <= nc.length; n++) {
s = range.getCell(i, n);
m.getRange(i, n).getCell(1, 1).setValue(s.getValue());
}
}
}
I have searched the code, but can't find anything wrong.
On google documentation at https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#insertsheetsheetname, it says ...
insertSheet(sheetName)
Inserts a new sheet into the spreadsheet with the given name. The new sheet becomes the active sheet.
In your code
function newSheet(master, name) {
var m = master.insertSheet(name); // after calling this function m becomes the active sheet
var sheet = SpreadsheetApp.getActiveSheet(); // you've assigned m to sheet
I would recommend using getSheetByName('SheetName').
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SheetName");
Refer to this link https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#getsheetbynamename
The obvious answer (Thanks #Rubén)
In the for loop, it says nc.length and nr.length. Both getNumRows and getNumColumns return numbers. Since these are integers, .length is not necessary.

Delete Duplicate Row in Google Spreadsheet

I need this script to delete the row (within the Registration sheet) with the matching Registration Code to the Cancel Registration sheet's Registration code. As of now, this script only deletes a row if "sheetR.deleteRow(i);" is not inside "if (regCodeR === regCodeCR) {}". It doesn't delete the correct row either.
function rD() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetR = ss.getSheetByName("Registration");
var sheetCR = ss.getSheetByName("Cancel Registration")
var dataR = sheetR.getDataRange().getValues();
var dataCR = sheetCR.getDataRange().getValues();
var headerRow = 1;
for (var i = 1; i in dataR && i in dataCR; ++i) {
var rowR = dataR[i];
var rowCR = dataCR[i];
var duplicate = false;
var regCodeR = sheetR.getRange(headerRow + i, 10).getValues();
var regCodeCR = sheetCR.getRange(headerRow + i, 9).getValues();
if (rowR[9] === rowCR[8]) {
duplicate = true;
}
}
if (regCodeR === regCodeCR) {
sheetR.deleteRow(i);
}
}
I tried this code with simple data having one column with registration numbers. You can modify the main sheet range according to your data. Also make sure to change the sheet names.
Tried and tested the code below :
function deleteDup(){
var mainSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('regis');
var cancelSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('cancel');
var mainSheetValues = mainSheet.getRange(2, 1, mainSheet.getLastRow(),1).getValues();
var cancelSheetValues = cancelSheet.getRange(2, 1, cancelSheet.getLastRow(),1).getValues();
var k = 0;
var del = [];
// Getting the row index of matching values
for (i = 0; i < cancelSheetValues.length; i++)
{
var cancelValue = cancelSheetValues[i][0];
Logger.log(cancelValue);
for (j = 0; j < mainSheetValues.length; j++)
{
if(mainSheetValues[j][0] == cancelValue){
del[k] = j;
k++;
}
}
}
del.sort();
var count =0;
// deleting the values from the main sheet values array
for (i = 0; i < k; i++ )
{
mainSheetValues.splice((del[i] - count), 1);
count++;
}
var len = mainSheetValues.length;
// Update the sheet with new values
mainSheet.getRange(2, 1, mainSheet.getLastRow(),1).clearContent();
mainSheet.getRange(2, 1, len,1).setValues(mainSheetValues);
}
But instead you can also do this way:
Set a flag value in the registration sheet if it matches with the cancellation sheet.
Then loop through the registration sheet data and delete the matching flag row.
Hope that helps!