My client wants to use Google Sheets instead of Excel. I could quickly write the code in VBA but am hitting a brick wall with Google Sheets.
H5 contains a drop-down list. I want the values in D5, D6, D7 and D8 to equal the value in H5 BUT only if a value has been selected in H5.
I have built my code based on similar examples I have seen on this website. I tried to debug my code but I didn't find the debugging tools in Google Sheets to be nearly as effective as in VBA.
function PercentageIncreases1() {
var spreadsheet = SpreadsheetApp.getActive();
var cell1 = ("H5");
var cell2 = ("H6");
var cell3 = ("H7");
var cell4 = ("H8");
if (cell1 > 0) {
spreadsheet.getRange('D5').activate();
spreadsheet.getCurrentCell().setFormula('=H5');
spreadsheet.getRange('D6').activate();
spreadsheet.getCurrentCell().setFormula('=H5');
spreadsheet.getRange('D7').activate();
spreadsheet.getCurrentCell().setFormula('=H5');
spreadsheet.getRange('D8').activate();
spreadsheet.getCurrentCell().setFormula('=H5');
}
};
If the value in H5 is 10, then I expect the values in D5, D6, D7, D8 to also be 10.
At the moment the values in D5, D6, D7 and D8 are not being updated.
Google Sheets use Google Apps Script for macros.
Google Apps Script is based on JavaScript
To create an if statement use JavaScript's if...else statement.
References
https://developers.google.com/apps-script/guides/sheets
Try this if this is what you are looking for,
function PercentageIncreases1()
{
var spreadsheet = SpreadsheetApp.getActive();
var cell1 = spreadsheet.getRange("H5").getValues();
var cell2= spreadsheet.getRange("H6").getValues();
var cell3= spreadsheet.getRange("H7").getValues();
var cell4= spreadsheet.getRange("H8").getValues();
if (cell1[0][0] > 0)
{
if(cell1[0][0] == 10)
{
spreadsheet.getRange("D5").setValue(cell1[0][0]);
spreadsheet.getRange("D6").setValue(cell1[0][0]);
spreadsheet.getRange("D7").setValue(cell1[0][0]);
spreadsheet.getRange("D8").setValue(cell1[0][0]);
}
else
{
}
}
};
Try this:
function onEdit(){
var ss = SpreadsheetApp.getActiveSheet();
var selection = ss.getRange("A1").getValue();
if (selection != "")
ss.getRange("D5:D8").setValue(selection);
}
I created a drop-down menu in A1 with a few number values to choose from. the code will check the selection, and if it's not empty, it will populate D5:D8 with the selected number. The function will run whenever the sheet gets edited.
since you're starting with Apps Script, I suggest you take a look at the SpreadsheetApp documentation as well as this introduction of App Scripts
Related
I'm very new to scripting in Google Sheets so my question may be either a lot more difficult than I think, or much simpler.
Basically, I have a Google Sheet that keeps track of a list of birthdays in one column, as well as what age group that person would belong to -- Child (under 13), Teen (13-17), or Adult (18+) -- in another column. The "Age Group" column is calculated using the following formula:
=IF(DATEDIF(H2, TODAY(), "Y") >= 18, "Adult", IF(DATEDIF(H2, Today(), "Y") >= 13, "Teen", "Child"))
with column H being the Birthday column.
My Google Sheet is set to recalculate the Today() function every hour, regardless of whether the file is open or not, so should a person's 13th or 18th birthday roll around, the Age Group column will update automatically.
My goal is to create a function that sends me an email whenever somebody's Age Group changes from Child to Teen or from Teen to Adult -- without requiring the Google Sheet to be opened by the user, or modified in any way, to trigger.
So far, I've been experimenting with "on edit" triggers, but I've noticed that this requires me to manually change an Age Group cell to trigger -- defeating the purpose of automation.
I've also tried changing my Trigger Event Type from "on edit" to "on change", hoping this would trigger the script whenever a cell in the Age Group column changes its resulting value, but this has not worked so far.
My code currently stands as follows (note that this code only makes a notice pop up rather than sending an actual email -- I haven't yet gotten to that part):
/*
This is the function that is triggered by an edit to
the Google Sheet
*/
function onEdit(e) {
sendEmailOnApproval(e);
}
/*
Primarily used for earlier debugging
*/
function showMessageOnApproval(e)
{
var edited_row = checkStatusIsApproved(e);
if(edited_row > 0)
{
SpreadsheetApp.getUi().alert("Row # "+edited_row+" approved!");
}
}
/*
Determines if the Age Group column reads Teen or Adult.
Column 9 (or 'I' in the sheet) is the Age Group column.
*/
function checkStatusIsApproved(e)
{
var range = e.range;
if(range.getColumn() <= 9 &&
range.getLastColumn() >=9 )
{
var edited_row = range.getRow();
var status = SpreadsheetApp.getActiveSheet().getRange(edited_row,9).getValue();
if(status == 'Adult' || status == 'Teen')
{
return edited_row;
}
}
return 0;
}
function sendEmailOnApproval(e)
{
var approved_row = checkStatusIsApproved(e);
if(approved_row <= 0)
{
return;
}
sendEmailByRow(approved_row);
}
/*
At the moment, this function only creates a little pop-up
box containing the text of the email I would like to send.
*/
function sendEmailByRow(row)
{
var values = SpreadsheetApp.getActiveSheet().getRange(row,1,row,9).getValues();
var row_values = values[0];
var mail = composeApprovedEmail(row_values);
SpreadsheetApp.getUi().alert(" subject is "+mail.subject+"\n message "+mail.message);
}
/*
Writes the email. Column 0 (or 'A') is the first name,
1 (or 'B') is the last name.
*/
function composeApprovedEmail(row_values)
{
var first_name = row_values[0];
var last_name = row_values[1];
var age = row_values[8];
var message = "The following person should be updated on the website: "+first_name+" "+last_name+
" Age Range: "+age;
var subject = "UPDATE WEBSITE for "+first_name+" "+last_name;
return({message:message,subject:subject});
}
While this code works when manually changing the values in the Age Range column, how can I adapt it to catch the automatic updates caused by daily recalculation of the Today() function the column relies on?
According to the Apps Script Trigger documentation:
onOpen(e) runs when a user opens a spreadsheet, document, presentation, or form that the user has permission to edit
onEdit(e) runs when a user changes a value in a spreadsheet
Therefore, what you are trying to do cannot be done by using the method that you were previously using since you were trying to use a trigger which would fire every time a change was made by a function (the Sheets formula) and not by a user.
Workaround
What you can do instead is to:
Use the Sheets formula you were previously using but change the Recalculation settings to On change instead of On change and every hour like you were previously doing.
In this way, you will still get the ages categorized based on the dates provided.
Use the following script:
function ageChanges(){
var ss = SpreadsheetApp.getActive().getActiveSheet();
var dateVals = ss.getRange("YOUR_RANGE_FOR_THE_DATES").getValues();
var ageVals = ss.getRange("YOUR_RANGE_FOR_THE_AGES").getValues();
var dateNow = new Date();
var recipient = "EMAIL_ADDRESS";
var subject = "Age Change in Spreadsheet";
var body = "";
for (var i=0; i<dateVals.length; i++){
var ages = (dateNow - dateVals[i][0])/(3.154e+10);
if (ages > 18 && ageVals[i][0]!="Adult") {
ss.getRange(i+1, 9).setValue("Adult");
body = "Change in column H, row"+i+".";
MailApp.sendEmail(recipient,subject,body);
}
else if (ages > 13 && ages < 18 && ageVals[i][0]!="Teen") {
ss.getRange(i+1, 9).setValue("Teen");
body = "Change in column H, row"+i+".";
MailApp.sendEmail(recipient,subject,body);
}
}
}
The script computes the ages based on the dates you have in your Spreadsheet. If the age does not match with the corresponding category, a mail will be sent with the changes made.
In order to monitor the changes daily you will have to use the above script as an installable trigger.
Create an installable trigger with the following options:
In this way, the script will run every day at the time of the day selected by you (in this case, Midnight to 1am) and if any age changes occur, you will receive the email(s) with the changes.
Furthermore, I suggest you take a look at these links since they might be of help in your future development:
Installable Triggers;
MailApp Class.
I"m pretty sure I'm doing something wrong in the code, as to why it's not functioning the way I want it. Firstly, here's the code:
function onEdit(a) {
var sheet = a.source.getActiveSheet();
var aa = SpreadsheetApp.getActiveSpreadsheet();
var COMP = aa.getSheetByName("COMP");
var COMPcell = sheet.getRange('B6').getValue();
if(COMPcell = 'TRUE'){COMP.showSheet();}else{COMP.hideSheet();}
}
In here, I have a checkbox on cell B6 of the 'active sheet' (named Monthly summary). When checked (and thus have a value of TRUE), I want the sheet named "COMP" to appear. Otherwise, it should be hidden. I'm not really good at coding and I've researched the above formula and modified it as to my requirement, but I can't get it to work.
Any insights on this will be very much appreciated. Thanks!
You want to show the sheet of COMP only when the checkbox of "B6" is checked.
You want to hide the sheet of COMP when the checkbox of "B6" is not checked.
If my understanding is correct, how about this modification? Please think of this as just one of several answers.
Modified script 1:
If your script is modified, in your script, COMPcell = 'TRUE' of the if statement is not compared the value. In this case, please modify to COMPcell === true. The modified script reflected this is as follows.
function onEdit(a) {
var sheet = a.source.getActiveSheet();
var aa = SpreadsheetApp.getActiveSpreadsheet();
var COMP = aa.getSheetByName("COMP");
var COMPcell = sheet.getRange('B6').getValue();
if (COMPcell === true) { // Modified
COMP.showSheet();
} else {
COMP.hideSheet();
}
}
Modified script 2:
When the event object and isChecked() are used, your script can also be modified as follows. In this script, only when the checkbox of "B6" is edited, the script works.
function onEdit(a) {
var range = a.range;
if (range.getA1Notation() == "B6") {
var COMP = a.source.getSheetByName("COMP");
if (range.isChecked()) {
COMP.showSheet();
} else {
COMP.hideSheet();
}
}
}
References:
if...else
isChecked()
Event Objects
Im working with google spreadsheet, and google script.
I have problem with for() function in array.
Its run 346++ seconds and failed.
I need to match data in two columns, and matched data is written in the same row that found, but another column i working have almost 30,000 rows and it takes forever.
Here is the code im working, i have tested it in smaller scale and its worked:
function check2dArray() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("2d array");
var dataInputValues = sheet.getRange("A:B").getValues();
var dataCheckValues = sheet.getRange("D:D").getValues();
var writeResultColumn1 = sheet.getRange("F:F").getColumn();
var writeResultColumn2 = sheet.getRange("G:G").getColumn();
//clearing data
sheet.getRange("F:G").clear();
for(i=0;i<dataInputValues.length;i++){
for(j=0;j<dataCheckValues.length;j++){
if(dataInputValues[i][0] == dataCheckValues[j][0] & dataInputValues[i][0] != "" & dataInputValues[i][0] != "#N/A" ) {
sheet.getRange(j+1, writeResultColumn1).setValue(dataInputValues[i][0]);
sheet.getRange(j+1, writeResultColumn2).setValue(dataInputValues[i][1]);
}
}
}
}
Im still new in this, maybe there is better way to solve?
Here is the screenshoot of my sheet
Sheet screenshoot
Code screenshoot
Here is Link to my sheet :
https://docs.google.com/spreadsheets/d/1DVbNaehsTWkiIkzW2nQx7w-ZB8CrPmSP5T5CpU24mbU/edit?usp=sharing
I have a loop that does what I want, but I would like to set an active cell in each sheet so I don't have to click it each time as I cycle through.
I've tried two ways that seem to make sense, but they both only work on the last sheet in the loop:-
function setDraft() {
//msg box to confirm relevant sheets are hidden, thus excluded from code
var response = Browser.msgBox("SET AS DRAFT","Have you hidden sheets you don't want marked as draft?", Browser.Buttons.YES_NO);
if(response=="no")
return;
else if(response=="cancel")
return;
else
//loop and code for Visible sheets
var ss = SpreadsheetApp.getActive();
var allsheets = ss.getSheets();
for (var s in allsheets){
var sheet=allsheets[s]
var date = sheet.getRange('I1')
if (sheet.isSheetHidden()!= true) {
//sheet.setActiveRange(date);
sheet.setActiveSelection(date);
sheet.getRange('I5').setValue('DRAFT');
}
}
}
Can anyone please let me know where I'm going wrong?
Thanks in advance!
Use the sheet.activate() or range.activate() methods. Use sheet method if you only care to go to a specific sheet, but if you want the select a specific cell then use it with range. I have not tested with range, however, I know that if you use sheet.activate() then you will be brought to that sheet.
Using for...in in JS can lead to problems (more on that in this post). Second, try using the built in UI class through the SpreadsheetApp class rather than the Browser buttons.
function setDraft() {
var ui = SpreadsheetApp.getUi();
var allsheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
//msg box to confirm relevant sheets are hidden, thus excluded from code
var response = ui.alert("SET AS DRAFT","Have you hidden sheets you don't want marked as draft?", ui.ButtonSet.YES_NO);
if(response == ui.Button.NO) {
return;
} else {
for (var s=0; s<allsheets.length; s++){
var sheet=allsheets[s]
var date = sheet.getRange('I1')
if (sheet.isSheetHidden()!= true) {
sheet.setActiveSelection(date);
sheet.getRange('I5').setValue('DRAFT');
}
}
}
}
I am currently using google forms to enable users to submit site changes. This is all working beautifully.
I have added an extra column that has ticket status. Now I have written a script that checks for when this is updated to Done and then moves that row into another sheet entitled done.
However this only works if i update a row that i manually added. If I change the column on a row created from the form entry it will not work. Has anyone seen this issue before. Code is below.
function onEdit(e){
/*
When a user updates a status to done the ticket gets moved to another sheet
*/
var sheetNameToWatch = "Form responses 1"; // The sheet to watch for changes
var columnNumberToWatch = 1; // The column where the change happens on the above sheet
var valueToWatch = "Done"; // What is the text you are looking for
var sheetNameToMoveTheRowTo = "Done"; // The Sheet name for where the row gets moved to.
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Get the active spreadsheet
var sheet = SpreadsheetApp.getActiveSheet(); // Get the active sheet
var range = sheet.getActiveCell(); // Get the current cell that has just been updated
// Check that you are on the correct sheet and column.
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo); // get a reference for the target sheet
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1); // get a reference for the target row
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange); // copy the row from current sheet to the new sheet
sheet.deleteRow(range.getRow()); // Delete the row from the old sheet
}
}
Yep, the onEdit function won't fire unless you do it manually, you'll want to use the onFormSubmit trigger, which will fire when a form response is received. This is a manually installed trigger connected to your form, which should be able to do the function above pretty much as written.
var form = FormApp.openById('1234567890abcdefghijklmnopqrstuvwxyz');
ScriptApp.newTrigger('myFunction')
.forForm(form)
.onFormSubmit()
.create();
To be safe, though, you may want to define your spreadsheet, sheet, and range by id or by name rather than by whether they are active, I believe getActiveWhatever() kinds of methods will return null if the spreadsheet isn't open.
As mentioned, using active is not the best idea.
Instead of:
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Get the active spreadsheet
var sheet = SpreadsheetApp.getActiveSheet(); // Get the active sheet
var range = sheet.getActiveCell(); // Get the current cell that has just been updated
Try:
var range = e.range;
var sheet = range.getSheet();
var ss = sheet.getParent();
If you try this you cannot execute it from the code editor because no event is passed. You must execute it by actually submitting a form.