Update cell using UI menu (Googe Sheets Scripts) - javascript

I'm trying to update a cells value dependent on on another cell in the same row. This is mean't to be done by the setRankID function, but no matter what I've tried it just spits out errors.
function onOpen() {
var ui = SpreadsheetApp.getUi();
var ss = SpreadsheetApp.getActiveSpreadsheet();
ui.createMenu('Daniagaming EMS Tools')
.addItem('Opdater RID\'s', 'setRankID')
.addToUi();
}
function setRankID() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sheet = ss.getActiveSheet(),
range = ss.range,
columnNumberToWatch = 1; // A = 1, B = 2 etc.
if(sheet.getName() === "Ark1" && range.columnStart === columnNumberToWatch) {
if(ss.value === "Commisioner") {
sheet.getRange(range.rowStart, 2).setValue("1");
}
}
}
What I wan't it to do is when using the function through the UI, to check cells in column A and update the value of column B dependent on column A's value.
Like if column A has the value "Test1" then column B should be set to the value "Toast".

Here's a simple example of what I think you were asking for. It's hard to tell because your setRankID function has a lot errors.
function simpleExample()
{
var ss=SpreadsheetApp.getActive();
var sht=ss.getSheetByName('deleteDupes');
var rng=sht.getDataRange();
var rngA=rng.getValues();
for(var i=1;i<rngA.length;i++)
{
if(rngA[i][0]=='Test1')
{
sht.getRange(i+1,2).setValue('Toast');
}
else
if(rngA[i][0])
{
sht.getRange(i+1,2).setValue(rngA[i][0]);
}
}
}
Here's what my spreadsheet looks like before running the function:
Here's what it looks like after:

Related

How to get last visible row, if rows are hidden or not hidden by filter in Google Sheets?

Only lastRow1 shows me the wrong value, if rows are hidden. How to ignore hidden rows?
function x() {
var s = SpreadsheetApp.getActive().getActiveSheet();
var lastRow1 = s.getLastRow();
var lastRow2 = s.getActiveRange().getLastRow();
Browser.msgBox(lastRow1);
Browser.msgBox(lastRow2);
if (lastRow1 == lastRow2) {
// Do something.
}
}
I believe your goal as follows.
When the following sample situation, you want to retrieve 5 as lastRow.
You want to achieve this using Google Apps Script.
For this, how about this answer?
Modification point:
In this case, lastRow is retrieved with isRowHiddenByUser.
Modified script:
function x() {
var s = SpreadsheetApp.getActive().getActiveSheet();
var lastRow = 0;
for (var i = s.getLastRow(); i > 0; i--) {
if (!s.isRowHiddenByUser(i)) {
lastRow = i;
break;
}
}
console.log(lastRow); // or Browser.msgBox(lastRow);
}
Note:
If you want to retrieve lastRow from the sheet with the hidden rows by the basic filter, please modify as follows.
From
if (!s.isRowHiddenByUser(i)) {
To
if (!s.isRowHiddenByFilter(i)) {
References:
isRowHiddenByUser(rowPosition)
isRowHiddenByFilter(rowPosition)

Google Script - Sending Email from drop-down

I am trying to fix a code I found online. My goal is that once the Summary tab, column I is edited with the drop-down "approved" for the sheet to send an email to the person on the name in column D.
The email is found in the range tab though. This is what I have so far...
var admin_email='taniapeche#gmail.com';
function triggerOnEdit(e)
{
sendEmailOnApproval(e);
}
function checkStatusIsApproved(e)
{ var sheet = SpreadsheetApp.getActive().getSheetByName('Summary');
var range = e.range;
if(range.getColumn() <= 9 &&
range.getLastColumn() >=9 )
{
var edited_row = range.getRow();
var status = SpreadsheetApp.getActiveSheet().getSheetName('Summary').getRange(edited_row,9).getValue();
if(status == 'Approved')
{
return edited_row;
}
}
return 0;
}
function sendEmailOnApproval(e)
{ var sheet = SpreadsheetApp.getActive().getSheetByName('Range');
var approved_row = checkStatusIsApproved(e);
if(approved_row <= 0)
{
return;
}
sendEmailByRow(approved_row);
}
function sendEmailByRow(row)
{
var values = SpreadsheetApp.getActiveSheet().getSheetName('Range').getRange(row,1,row,5).getValues();
var row_values = values[0];
var mail = composeApprovedEmail(row_values);
//SpreadsheetApp.getUi().alert(" subject is "+mail.subject+"\n message "+mail.message);
MailApp.sendEmail(admin_email,mail.subject,mail.message);
}
function composeApprovedEmail(row_values)
{
var first_name = row_values[1];
var last_name = row_values[2];
var email = row_values[3];
var message = "The following mileage is approved: "+first_name+" "+last_name+
" email "+email;
var subject = "Mileage approved "+first_name+" "+last_name
return({message:message,subject:subject});
}
This is how to sheet looks:
https://docs.google.com/spreadsheets/d/1lWORvuwAHducEIiL-VVidJ-wjujE344udPbWCZpE1kw/edit?usp=sharing
Thanks for the help :)
First of all, because you want the script to send an email (an action which requires your authorization), you have to install the edit trigger, either manually or programmatically. If you do it programmatically, you can install the trigger by running this function once:
function createTriggerOnEdit(e) {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger("sendEmailOnApproval")
.forSpreadsheet(ss)
.onEdit()
.create();
}
As a result of this, the function sendEmailOnApproval will fire every time the spreadsheet is edited. This function could be something along the following lines (check inline comments for detailed explanation):
function sendEmailOnApproval(e) {
// Get the edited range and sheet using the event object:
var range = e.range;
var editedSheet = range.getSheet();
var textToSearch = "Approved"; // Set which value will cause the email to be sent
// Check that edited cell is in column I, its value is "Approved" and its sheet is "Summary":
if (range.getColumn() === 9 && range.getValue() === textToSearch &&
editedSheet.getName() === "Summary") {
var rowIndex = range.getRow(); // Get index of the edited row
var name = editedSheet.getRange(rowIndex, 4).getValue(); // Get corresponding name in column D
var rangeValues = e.source.getSheetByName("Range").getDataRange().getValues(); // Get values in sheet "Range"
// Iterate through the rows in "Range", looking for the name retrieved from sheet "Summary"
for (var i = 0; i < rangeValues.length; i++) {
var rowValues = rangeValues[i];
if (name === rowValues[0]) { // Check if name matches the one in column D from "Summary"
var mail = composeApprovedEmail(rowValues); // Compose email (your function)
MailApp.sendEmail(admin_email, mail.subject, mail.message); // Send email
return; // End execution so that the script stops iterating through the rows in "Range"
}
}
}
}
Notes:
The function composeApprovedEmail is called in this sample. It's the same as the one you provided. The rest of functions you provided are not used.
Reference:
Installable Triggers
Event Objects: Edit

How to have onFormSubmit(e) and onEdit(e) together nested

I want onFormSubmit(e) to be my main function trigger and within that I want onEdit(e) to be nested. Basically, no matter, the trigger will run onFormSubmit but it will do others within the onEdit if there is any edit, if there isn't then it will do something else.
I can't see to understand and make it work.
My script triggers shows onFormSubmit as the only function and onEdit is not in the dropdown.
function onFormSubmit(e){
ScriptApp.newTrigger("onEdit").timeBased().after(60000).create();
function onEdit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet().getRange('SpeedVSD');
var sheet = ss.getSheetByName("Responses 1");
var row = ss.range.getRow();
var col = ss.range.getColumn();
if (col >= ss.getColumn() && col <= ss.getLastColumn() && row >= ss.getRow() && row <= ss.getLastRow()){
console.log("You edited a Cell within Range");
}
}
edit: Managed to get my lastRow value. However, I am still looking to get a command that can get the lastRow value for all the columns instead of manually doing it.
edit: Using a FOR Loop helps with collating the values.
//This is to get the Last Row on Column 2 value.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheetByName('FIRST');
var row = sheets.getLastRow();
for(var i = 1; i <= sheets.getLastColumn(); i++){
var myID = sheets.getRange(row, i).getValue();
}
console.log("Row Number: "+row);
console.log("Content of last Row: "+myID);```
If you want the onEdit() to run always, you just create it as a separate function. then you can call it from the onFormSubmit(), like this:
function onFormSubmit(e){
//does something you need...
onEdit();
}
onEdit(e){
//do the onEdit code...
}
The only problem with this is that the event e for onFormSubmit() is different than the one for onEdit(), so working with events might not be the best idea. However, calling one function from the other would fun just like with any other function.
function onFormSubmit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheetByName('FIRST');
var row = sheets.getLastRow();
var myIDCol2 = 2;
var myIDCol3 = 3;
var myID2 = sheets.getRange(row, myIDCol2).getValue();
var myID3 = sheets.getRange(row, myIDCol3).getValue();
console.log("Speed Before Trigger Value: "+myID2);
console.log("Voltage Before Trigger Value: "+myID3);
ScriptApp.newTrigger("responsechange").timeBased().after(60000).create();
}
function responsechange(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheetByName('FIRST');
var row = sheets.getLastRow();
var myIDCol2 = 2;
var myIDCol3 = 3;
/*for(var i = 1; i <= sheets.getLastColumn(); i++){
console.log("Content of last Row: "+myID);
}*/
var myID2 = sheets.getRange(row, myIDCol2).getValue();
var myID3 = sheets.getRange(row, myIDCol3).getValue();
var template1 = HtmlService.createTemplateFromFile("speed1");
var template2 = HtmlService.createTemplateFromFile("voltage");
template1.speed1 = myID2;
template2.voltage = myID3;
console.log("Speed After Trigger Value: "+myID2);
console.log("Voltage After Trigger Value: "+myID3);
if((myID2 >=100) || (myID2 <= 50)){
MailApp.sendEmail("someone#gmail.com","Out of Range Notification Speed","",{htmlBody: template1.evaluate().getContent()});
}
if((myID3 >=100) || (myID3 <= 50)){
MailApp.sendEmail("someone#gmail.com","Out of Range Notification Voltage","",{htmlBody: template2.evaluate().getContent()});
}
}
With this, I managed make it work whereby on form submit, lets say the values are below 50 and above 100, it will trigger an email after the time-based trigger. I also tried within the time-based trigger, I edited the values to be within the range and it did not send an email. However, the only problems now is, if there are many triggers, it will stop the trigger by saying
This script has too many triggers. Triggers must be deleted from the script before more can be added.
But on the bright side, I managed to get the last value submitted to have it checked if it was edited or not.

How do I run Google script on multiple sheets?

I've seen this question return quite a few results here, but I'm having trouble getting it to work for my use case. Basically, I have a simple script that I want to run on multiple sheets in my spreadsheet (not every sheet, just the ones I define). I've tried defining the sheets and running a for loop, but it fails when calling the method getRange. Anyway, here's my original script that defines only one sheet, and this works as expected:
var sheetToSort = "Sheet1";
var columnToSortBy = 1;
var rangeToSort = "A2:AB";
function onEdit() {
var sheet = SpreadsheetApp.getActiveSheet();
var editedCell = sheet.getActiveCell();
if (editedCell.getColumn() == columnToSortBy && sheet.getName() == sheetToSort) {
sortFormResponsesSheet();
}
}
function sortFormResponsesSheet() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetToSort);
var range = sheet.getRange(rangeToSort);
range.sort( { column : columnToSortBy, ascending: false } );
}
This is an example of putting settings into an object and then looping through the object.
function onEdit() {
const sheet = SpreadsheetApp.getActiveSheet(),
editedCell = sheet.getActiveCell(),
editedColumn = editedCell.getColumn(),
sheetName = sheet.getName();
// Define all the sheets to sort using an object literal
const objSheetsToSort = {
"Sheet1": {columnToSortBy: 1, rangeToSort: "A2:AB"},
"Sheet2": {columnToSortBy: 2, rangeToSort: "A2:AB"},
"Sheet3": {columnToSortBy: 3, rangeToSort: "A2:AB"},
"Sheet4": {columnToSortBy: 4, rangeToSort: "A2:AB"}
}
// Get the sort info for this sheet (or `undefined` if we didn't define how to sort the edited sheet).
var config = objSheetsToSort[sheetName];
if (config && editedColumn === config.columnToSortBy) {
// We want to sort the edited sheet.
sortSheet_(sheet, config);
}
}
// This function can only be called by other functions in this Script Project, not manually or via menu.
function sortSheet_(sheetToSort, objectOfSettings) {
Logger.log('sheetToSort: ' + sheetToSort.getName())
var range = sheetToSort.getRange(objectOfSettings.rangeToSort);
range.sort( { column : objectOfSettings.columnToSortBy, ascending: false } );
}

A google spreadsheet script that triggers on edit of a column in a sheet and overwrites the value of a user defined cell or not depending on the value

Hope you are all well.
I am trying to write this nice script for my office because my colleagues lack a bit of discipline.
This script should trigger if a column in a sheet is edited, preferably, but it's fine if it trigger on sheet edit or maybe even on spreadsheet edit. This script should look at the value in that column of that sheet and if any of them have the strings "On hold(i)","On hold(ii)" or "On hold(iii)" then the cell on another column (chosen by the user) on the same row should be overwritten with the string "TBC". I tried piecing this from google and below is what I got but since I am here that obviously doesn't work haha. Any help would be greatly appreciated !! :((
function OnEdit() {
var a=1;
var ss = SpreadsheetApp.getActiveSpreadsheet();
while ( a<200 ){
if ( ss.getSheetByName('Active Jobs').getRange(a,12) == "On hold (i)" ) {
ss.getSheetByName('Active Jobs').getRange(a,15).setValues("TBC");
a=a+1;
}
}
}
I read somewhere on google that naming the funciton OnEdit would make the function trigger if the spreadsheet was edited but it doesn't seem to work.
function OnEdit() {
var a=1;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var activeCell = activeSheet.getActiveCell();
//Check if the sheet is a JOb sheet and the cell us the status cell
if (activeSheet.getName().indexOf("Job ID") != -1 && activeCell.getRow() == 2 && activeCell.getColumn() == 15){
var switchValue = activeCell.getValue();
switch (switchValue){
case "On hold (i)":
case "On hold (ii)":
case "On hold (iii)":
case "To be assigned":
//Write date to active jobs sheet
addDateToActive("TBC");
break;
case "In progress":
var newDate = Browser.inputBox("Please enter report out date");
addDateToActive(newDate);
break;
default:
Browser.msgBox("GOTHERE");
}
}
}
function addDateToActive(input){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var activeCell = activeSheet.getActiveCell();
var jobid = activeSheet.getRange(2,1).getValue().toString();
var activeJobSheet = ss.getSheetByName("Active Jobs");
var activeJobs = activeJobSheet.getRange(1,1,activeJobSheet.getLastRow(),1).getValues();
activeJobs = ColumnToArray(activeJobs);
var jobrow = activeJobs.indexOf(jobid)+1;
if (jobrow == -1){
Browser.msgBox("Job Id not preent on Active Jobs sheet");
}else{
activeJobSheet.getRange(jobrow,15).setValue(input);
}
}
function ColumnToArray(columnData){
//Ensure that the data supplied is a column
if(columnData[0].length == 1){
//Convert column to array
var dataout = [];
for (var a = 0; a < columnData.length; a++){
dataout.push(columnData[a][0]);
}
}else{
throw new Error("Data Supplied to ColumnToArray was not a simple Column");
}
return dataout;
}

Categories