Mutliple Selection Drop down applied to multiple sheets - google-sheets

I have the below code that works a treat on one sheet for selecting multiple options into one cell from a dropdown list, but I am borrowing code and I am not a code monkey so is there a way to do this function and apply it to multiple sheets?
Its the same column across the multiple sheets
function onEdit(e) {
var oldValue;
var newValue;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeCell = ss.getActiveCell();
if (activeCell.getColumn() == 3 && activeCell.getRow() == 1 && ss.getActiveSheet().getName() == "Sheet1") {
newValue = e.value;
oldValue = e.oldValue;
if (!e.value) {
activeCell.setValue("");
} else {
if (!e.oldValue) {
activeCell.setValue(newValue);
} else {
if (oldValue.indexOf(newValue) < 0) {
activeCell.setValue(oldValue + ',' + newValue);
} else {
activeCell.setValue(oldValue);
}
}
}
}
}
Any help would be greatly appreciated.
Thanks

Remove && ss.getActiveSheet().getName() == "Sheet1". It's a condition that makes the code work only in the sheet names Sheet1.

Related

Sending an email automatically when the edited cell value says "Done" and the email subject is the first cell in the edited row

I'm trying to write a script where an automatic email is sent to a specific person upon edit of a cell and the cell equals "Done". However, I want the subject to be the first cell of the edited row. Cell that will contain "Done" is always going to be in the AA Column, and I want the subject to be the A column of the same row. Ex: AA3 was edited so subject is A3. I have spent hours sifting through tutorials and came up with this:
function checkValue() {
var sp = PropertiesService.getScriptProperties();
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Accts");
var valueToCheck = sheet.getRange("AA2:AA1000").getValue();
if (valueToCheck = 'Done') {
MailApp.sendEmail("a***a#gmail.com", activeCell.offset(-26,0).getValue(), Email.html);
}
}
Am I doing this entirely wrong or is there hope?
EDIT:
Now that it's resolved. I thought I'd share what my script ended up looking like. I added a UI and an option to execute using a menu option. Hope this helps someone else.
function onEdit(e)
{
var editRange = { // AA2:AA1000
top : 2,
bottom : 1000,
left : 27,
right : 27
};
// Exit if we're out of range
var thisRow = e.range.getRow();
if (thisRow < editRange.top || thisRow > editRange.bottom) return;
var thisCol = e.range.getColumn();
if (thisCol < editRange.left || thisCol > editRange.right) return;
var thisthang = e.value;
var doit = 'TRUE'
// We're in range; timestamp the edit
if(thisthang == doit)
{
doFinish();
}
else{return};
}
function onOpen()
{
var ui = SpreadsheetApp.getUi();
ui.createMenu('Finished')
.addItem('Finish', 'doFinish')
.addToUi();
}
function doFinish()
{
var cell = SpreadsheetApp.getActiveSheet().getActiveCell();
var row = cell.getRow();
var Campaign = getCampaignFromRow(row, 1);
var ui = SpreadsheetApp.getUi();
var response = ui.alert('Finish '+Campaign.name+'?', ui.ButtonSet.YES_NO);
if(response == ui.Button.YES)
{
handleFinish(row, Campaign);
}
if(response == ui.Button.NO)
{
SpreadsheetApp.getActiveSheet().getRange(row, 27).setValue('FALSE');
}
}
function getCampaignFromRow(row)
{
var values = SpreadsheetApp.getActiveSheet().getRange(row, 1).getValues();
var rec = values[0];
var Campaign =
{
Campaign_Name: rec[0]
};
Campaign.name = Campaign.Campaign_Name;
return Campaign;
}
function handleFinish(row, Campaign)
{
var templ = HtmlService
.createTemplateFromFile('Campaign-email');
templ.Campaign = Campaign;
var message = templ.evaluate().getContent();
MailApp.sendEmail({
to: "a***a#gmail.com",
subject: "A Campaign has been finished!",
htmlBody: message
});
SpreadsheetApp.getActiveSheet().getRange(row, 27).setValue('TRUE');
}
You are trying to trigger an email when the spreadsheet is edited on the "Accts" sheet, in Column "AA" and the value = "Done".
The best solution is to use an onEdit trigger and also make use of Event Objects. In the case, "a simple trigger cannot send an email" ref, so you will need to create an Installable Trigger.
The main differences to your script are:
- var valueToCheck = sheet.getRange("AA2:AA1000").getValue();
- a couple of things here.
- 1) you are trying to get all the values in the column, but you use the getValue (the method for a single cell) instead of getValues.
- 2) you could have defined the ActiveCell and just returned that value
- 3) though you tried to get the values for the entire column, your if statement is designed as though there is a single value rather than an array of values.
- 4) This demonstrates the benefit of the using the Event Objects. You can succinctly get the values of the edited cell and sheet.
- in your if comparison, you use "="; this is only used to assign a value. When comparing values you must use "==" or "===".
- To get the value of the "subject", the script uses the row number derived from the Event Objects; compared to the offset in your script - they are both acceptable. I used the getRange to demonstrate the alternative.
- your email body was defined as "Email.html", but this isn't declared. The answer uses a very simple body but could just as easily use another solution.
function so5967209001(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet()
// establish the values to be checked
var checkSheetname = "Accts"
var checkValue = "Done"
var checkColumn = 27; // column AA
// this will return the event objects
//Logger.log(JSON.stringify(e)); // DEBUG
// variables to use for checking
var editedrange = e.range;
var editedrow = editedrange.getRow();
var editedcolumn = editedrange.getColumn();
var editedsheet = editedrange.getSheet().getSheetName();
var editedvalue = e.value;
//Logger.log("DEBUG: row = "+editedrow+", column = "+editedcolumn+", sheet = "+editedsheet+", value"+editedvalue)
// test the sheet, the column and the value
if (editedsheet ==checkSheetname && editedcolumn==checkColumn && editedvalue == checkValue){
//Logger.log("DEBUG: this is a match");
var subject = sheet.getRange(editedrow,1).getValue(); // Column A of the edited row
//Logger.log("DEBUG: email subject = "+subject);
// build your own body
var body = "this is the body of the email"
// send the email
MailApp.sendEmail("ejb#tedbell.com.au", subject, body);
//Logger.log("DEBUG: mail sent")
}else{
//Logger.log("DEBUG: this isn't a match");
}
}

How do I make my script work only in specific rows?

I have an automated time stamp script that works when clicking a checkbox, a time stamp is populated in the cell next to it. How do I make my script work on certain rows?
Example: Column C has check boxes, Column D is populated with dates when Check boxes are marked.
What I want my TimeStamp script to do:
Work only on Row 11, all the way down.
var COLUMNTOCHECK = 3;
var DATETIMELOCATION = [0, 1];
var SHEETNAME = 'Training Dash'
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
if( sheet.getSheetName() == SHEETNAME ) {
var selectedCell = ss.getActiveCell();
if (selectedCell.getColumn() >= COLUMNTOCHECK && selectedCell.getColumn() % 2 == 1) {
var dateTimeCell = selectedCell.offset(DATETIMELOCATION[0],DATETIMELOCATION[1]);
dateTimeCell.setValue(new Date());
}
}
}
if I understood correctly, this should help.
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
if( sheet.getSheetName() == SHEETNAME ) {
var selectedCell = ss.getActiveCell();
if (selectedCell.getColumn() >= COLUMNTOCHECK && selectedCell.getColumn() %
2 == 1 && selectedCell.getRow() > 10) {
var dateTimeCell =
selectedCell.offset(DATETIMELOCATION[0],DATETIMELOCATION[1]);
dateTimeCell.setValue(new Date());
}
}
}

Auto hide/unhide rows Google Spreadsheet

I'm trying to make a google spreadsheet script.
When the value of a cell changes to a specified value I want it to trigger hide/unhide rows.
Here is my script so far:
function autoHide() {
var ss = SpreadsheetApp.getActive()
var sheet = SpreadsheetApp.getActiveSheet()
var cell = ss.getActiveCell()
var cell1 = ("C12");
if (cell1 == "Others" ) {
ss.getActiveSheet().showRows(14, 3);
}
else if (cell1 == "Additional Discount/s (over and above 25%)" ) {
ss.getActiveSheet().showRows(17, 4);
}
else {
ss.getActiveSheet().hideRows(14, 7)
}
}
Your question is a little unclear about some points so I assumed you wanted to track the value of cell C12 when C12 is edited.
function autoHide() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var cell = ss.getActiveCell();
var value = cell.getValue();
var cellRef = cell.getA1Notation();
if (cellRef !== "C12") return;
// This isn't the cell we are looking for, stop executing the function.
if (value === "Others" ) {
sheet.showRows(14, 3);
} else if (value === "Additional Discount/s (over and above 25%)" ) {
sheet.showRows(17, 4);
} else {
sheet.hideRows(14, 7);
}
}
If you want to run the function anytime any cell is edited, use this code.
Useful if C12 is a formula and is not updated manually.
function autoHide() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var cellRef = "C12";
var cell = sheet.getRange(cellRef);
var value = cell.getValue();
if (value === "Others" ) {
sheet.showRows(14, 3);
} else if (value === "Additional Discount/s (over and above 25%)" ) {
sheet.showRows(17, 4);
} else {
sheet.hideRows(14, 7);
}
}

Random number from an array without repeating the same number twice in a row?

I am making a game using Swift and SpriteKit where i move an object to random locations based on an array.
The array that is made up of CGPoints:
let easyArray = [CGPointMake(0,0), CGPointMake(126.6,0), CGPointMake(253.4,0), CGPointMake(0,197.5), CGPointMake(126.7,197.5), CGPointMake(253.4,197.5), CGPointMake(0,395), CGPointMake(126.7,395), CGPointMake(253.4,395)]
I use this function to generate a random number:
func randomNumber(maximum: UInt32) -> Int {
var randomNumber = arc4random_uniform(maximum)
while previousNumber == randomNumber {
randomNumber = arc4random_uniform(maximum)
}
previousNumber = randomNumber
return Int(randomNumber)
}
I used this to move the object based on the random number generated:
let greenEasy = randomNumberNew(9)
let moveSelector = SKAction.moveTo(easyArray[greenEasy], duration: 0)
selector.runAction(moveSelector)
I have done some reading online and found that the "While" condition should make it so that the same random number isn't generate twice in a row. But it still happens.
Can anyone please help me on how to make it so i don't get the same number twice in a row?
The code below doesn't random the same number.
var currentNo: UInt32 = 0
func randomNumber(maximum: UInt32) -> Int {
var randomNumber: UInt32
do {
randomNumber = (arc4random_uniform(maximum))
}while currentNo == randomNumber
currentNo = randomNumber
return Int(randomNumber)
}
I think Larme's suggestion is pretty clever, actually.
easyArray.append(easyArray.removeAtIndex(Int(arc4random_uniform(UInt32(easyArray.count)-1))))
selector.runAction(SKAction.moveTo(easyArray.last!, duration: 0))
I would recommend to not use while() loops with randomizers.
Theoretically it can cause infinite loops in worst case scenario, in more positive scenario it will just take few loops before you get desired results.
Instead I would advice to make an NSArray of all values, remove from this NSArray last randomized element and randomize any of other existing elements from such an array - that is guarantee result after only one randomize iteration.
It can be easily achieved by making NSArray category in Objective-C:
- (id) randomARC4Element
{
if(self.count > 0)
{
return [self objectAtIndex:[self randomIntBetweenMin:0 andMax:self.count-1]];
}
return nil;
}
- (int)randomIntBetweenMin:(int)minValue andMax:(int)maxValue
{
return (int)(minValue + [self randomFloat] * (maxValue - minValue));
}
- (float)randomFloat
{
return (float) arc4random() / UINT_MAX;
}
If you can use linq then you can select a random value that doesn't match the last value. Then for any left over values you can loop through and find valid places to insert them.
It's not the most efficient but it works.
public static List<int> Randomize(List<int> reps, int lastId) {
var rand = new Random();
var newReps = new List<int>();
var tempReps = new List<int>();
tempReps.AddRange(reps);
while (tempReps.Any(x => x != lastId)) {
var validReps = tempReps.FindAll(x => x != lastId);
var i = rand.Next(0, validReps.Count - 1);
newReps.Add(validReps[i]);
lastId = validReps[i];
tempReps.Remove(validReps[i]);
}
while (tempReps.Any()) {
var tempRep = tempReps.First();
bool placed = false;
for (int i = 0; i < newReps.Count; i++) {
if (newReps[i] == tempRep) {
continue;
}
else if ((i < newReps.Count - 1) && (newReps[i + 1] == tempRep)) {
continue;
}
else {
newReps.Insert(i + 1, tempRep);
placed = true;
break;
}
}
if (placed) {
tempReps.Remove(tempRep);
}
else {
throw new Exception("Unable to randomize reps");
}
}
return newReps;
}

Script is working ONLY in step-by-step

here the file
https://docs.google.com/spreadsheet/ccc?key=0AurtxTJwggIpdG9GaE1TOV9wMEw2UHhjZVJyUXVETUE
you'll find on sheet Key, what is meant to do :
Find in all sheets, first in column B the row where the reference (Key!B1) stands, then starting from this row, find in column C where the reference (Key!B2) stands for first
in other words, we are looking for the couple and make the cell in column C as activecell
the script is working in debug mode, only
running it using the button in sheet Key, make it "not select" the good cell, even if the cell to be selected is found (logged in Logger)
I use a color function
That mean, blue or red is the cell to be selected , and sometimes it's not selected
the code :
function lookFor() {
var ss=SpreadsheetApp.getActiveSpreadsheet();
var referSheet=ss.getSheetByName("Key");
var sheetToCheck = new Array;
sheetToCheck[0]=ss.getSheetByName("work");
sheetToCheck[1]=ss.getSheetByName("user");
sheetToCheck[2]=ss.getSheetByName("tax");
sheetToCheck[3]=ss.getSheetByName("cont");
sheetToCheck[4]=ss.getSheetByName("ind");
var referenceB=referSheet.getRange("B1").getValue();
var referenceC=referSheet.getRange("B2").getValue();
//loop to work with all reference as long as there are data in the column A
for (j in sheetToCheck){
sheetToCheck[j].setActiveCell("A1");
var dataToCheck=new Array;
dataToCheck=sheetToCheck[j].getRange(1,2,sheetToCheck[j].getLastRow(),2).getValues();
for (i in dataToCheck){
var done=false;
if (dataToCheck[i][0]==referenceB){
for (k=i;k<dataToCheck.length;k++){
if (dataToCheck[k][1]==referenceC){
//this part is user to change the color of the cell, to check if the code is working well
if (sheetToCheck[j].getRange(parseInt(k)+1,3,1,1).getBackgroundColor()=="red"){
sheetToCheck[j].getRange(parseInt(k)+1,3,1,1).setBackgroundColor("blue");
}
else
{
sheetToCheck[j].getRange(parseInt(k)+1,3,1,1).setBackgroundColor("red");
}
var cell=sheetToCheck[j].getRange(parseInt(k)+1,3,1,1).getA1Notation() ;
sheetToCheck[j].setActiveCell(cell);
SpreadsheetApp.flush();
done=true;
Logger.log("Sheet :"+sheetToCheck[j].getName()+" - Cell :"+cell);
break;
}
}
if (done==true){
break;
}
}
}
}
}
enter code here
I noticed you aready fixed this in your script:
var referenceB=referSheet.getRange("B1").getValue(); //A2
var referenceC=referSheet.getRange("B2").getValue(); //B2
Here is a shorter version of your code :)
function LookForCity() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var referSheet = ss.getSheetByName("Key").getDataRange().getValues()[1];
var sheetName = ["work", "user", "tax", "cont", "ind"];
for (j in sheetName){
var sheet = ss.getSheetByName(sheetName[j]);
var values = sheet.getDataRange().getValues();
for(i in values){
if(values[i][1] == referSheet[0] && values[i][2] == referSheet[1]){
Logger.log('Sheet: ' + sheetName[j]+ ' Cell: C'+(parseInt(i)+1) );
sheet.setActiveCell(sheet.getRange(parseInt(i)+1, 3));
Utilities.sleep(3000);
break;
}
}
}
}

Resources