How can i get this Script to run onEdit - javascript

I am trying to get this to run automatically, however with the current form it only works if i manually run the code.
I have another code file in this sheet which also uses onEdit, how can I incorporate the same onEdit to this code or make it run whenever column G is selected "Complete" to then change column H to "shipped"
function addValidation() {
// Get the spreadsheet and active sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
// Get the data as an Array you can iterate and manipulate
var data = sheet.getDataRange().getValues();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(["Complete"]).build();
// Loop the sheet
for(var i=0; i<data.length; i++) {
if(data[i][11] == "Complete") {
sheet.getRange(i+1, 8).clear().setDataValidation(rule);
} {
sheet.getRange(i+1, 8).clearDataValidations().setValue("Shipped");
}
}
}

A couple things:
In your if statement, you're not checking Column G - you're checking column K (11). If you want to check G, you need to change your if to:
if(data[i][6].toString() == "Complete") {
...
}
Your logic is backward and you're missing the else keyword to run the alternative. As is, it will mark 'Shipped' if it doesn't match 'Complete.' Swap the statements to fill the cell values correctly.
Also, string checking in a loop is a little tricky. Cell references as indices are objects, not strings. You need to convert your cell using the .toString() method before you can compare a straight string.
Your whole script should read:
function addValidation() {
// Get the spreadsheet and active sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
// Get the data as an Array you can iterate and manipulate
var data = sheet.getDataRange().getValues();
// Loop the sheet
for(var i=0; i<data.length; i++) {
// To change which columns you're testing, change the second value.
// ColG = 6, not 11.
// Convert data[i][6] using .toString() to compare the value
if(data[i][6].toString() == "Complete") {
// If it's "Complete," mark Col H as 'Shipped'
sheet.getRange(i+1, 8).setValue("Shipped");
} else {
// If you want something else to happen, add that here.
}
}
}
The last step is to enable a trigger for the script. If you name your function onEdit(), it will run by itself because editing is a simple script. Since it's called addValidation, you need to manually add the onEdit trigger in the UI. Go to Edit > Current Project Triggers and click on "Add Trigger" in the bottom right. Follow the steps in the UI and the script should run itself.

Related

Removing duplicate rows using Google App Scripts

I have a Google Sheet with two tabs that I want to check rows and delete duplicates from. However, the requirement for both is slightly different.
On tab submittedMatches I have data imported from a Google Form into columns A:C where a script on form submit then grabs data from an API and populates D:J and finally, K:M has a custom formula inserted via a script. The range of data being A2:M
The problem I am having is that a) I'm new to all of this, and b) when I try to remove duplicates (people can submit the same thing twice from the form) the only solution I have found copies all the rows, removes the duplicates and pastes the unique rows again so I lose the formulas.
I have the script checking columns B (this just has a letter from A-Z) and C (a unique ID) for duplicates, e.g., If row 2 and 3 have an "A" in column B and "123456" in column C, then this is a duplicate. For reference, this is what I had working:
function removeDuplicates() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var newData = [];
for (var i in data) {
var row = data[i];
var duplicate = false;
for (var j in newData) {
if(row[2] == newData[j][2] && row[3] == newData[j][3]){
duplicate = true;
}
}
if (!duplicate) {
newData.push(row);
}
}
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
What I need to happen is the script check for the duplicate rows based on data in columns B and C and remove them, but the formula in K:M must be preserved. Either by just removing the data from A:J or by another method.
Additionally, I'm assuming I need to make sure this is only run on the tab 'submittedMatches' and not other tabs on the sheet.
I solved this. Sorry. Always the way when you eventually ask for help after hours of trying.
I set a conditional format on B and C with: =countifs($B$1:$B1,$B1,$C$1:$C1,$C1)>1
I set the background colour to #fefefe and made the font red and bold. I then added the below script to check for cells with a #fefefe background and remove them.
function deleteDuplicateMatches() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName('submittedMatches');
//Only get range with data (non-empty cells)
var firstCol = sheet.getDataRange();
//Save data validation rules based on the first row
var dataValRules = sheet.getRange('A2:M2').getDataValidations();
var maxRow = firstCol.getNumRows();
for (var row=1; row<=maxRow; row++){
//Delete row with background color of gray #fefefe
if(sheet.getRange(row,1).getBackground() == "#fefefe"){
sheet.deleteRow(row);
//since current row was deleted adjust current data set
//this will handle scenarios with succeeding duplicates
row--;
maxRow--;
//insert new row at the end and set data validation rules
sheet.insertRowAfter(maxRow);
sheet.getRange(maxRow,1,1,13).setDataValidations(dataValRules);
}
}
};

I want to avoid duplicate dates in google sheets by using a script

I just signed up and need help with a problem, I am new to the google app scripts and I am struggling to create a script to avoid duplicate date.
The sheet will capture data once a day and to avoid duplicate dates I am trying to write a script.
I have looked at different methods, tried arrays and that also wont seem to work.
I created a small test site to explain here with the current issue I am facing.
Below is the code when the user clicks a save button, please not I am only struggling with the if statement. I get all the dates but I am unable to break it into separate dates in order to do the if statement.
In your code the variable values is indeed an array retrieved from your sheet using getValues()
You can manipulate that array as you loop through it removing the duplicate based on your variable names date or load into a separate array
var i = 0;
var lenValues = values.length;
var newArray = [];
for (i = 0; i < lenValues; i++) {
if (date !== values[i]) {
newArray.push(values[i]);
}
}
Now, dates can be tricky, I would use the debugger and set a breakpoint to inspect the data format stored in the values variable and adjust accordingly.
Once you have the new array, you may decide to write those values to another sheet
writeDataToSheet(newArray, "Target sheet name");
// Writes a 2D array of data to sheet
function writeDataToSheet(data, sheetName) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
goToSheet(sheetName, ss);
var sheet = ss.getActiveSheet();
var range = sheet.getRange("A1:A");
range.clear();
// write date to active sheet starting at the 2nd row
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
return sheet.getName();
}
function goToSheet(sheetName, ss) {
ss.setActiveSheet(ss.getSheetByName(sheetName));
}
Now, if all you want to do is alert the user the data already exists try this instead:
var i = 0;
var found = false;
var lenValues = values.length;
for (i = 0; i < lenValues; i++) {
if (date == values[i]) {
found = true;
break;
}
}
Put this before your if statement and change to:
if (found) {
}
This code will work to remove duplicates. My original dates are in C9:C16
The problem here is that it has converted the dates into strings, you may need to convert back to dates.
function removeDuplicate(){
var sheet = SpreadsheetApp.getActive().getActiveSheet();
let originalDates = sheet.getRange('C9:C16').getDisplayValues().flat();
console.log(originalDates);
let datesNoDup = originalDates.filter((date,i) => originalDates.indexOf(date) == i);
console.log(datesNoDup);
}
7:14:26 AM Notice Execution started
7:14:27 AM Info [ '2/1/2011',
'2/1/2011',
'2/25/2011',
'3/17/2011',
'7/25/2011',
'10/19/2011',
'3/17/2011',
'7/25/2011' ]
7:14:27 AM Info [ '2/1/2011',
'2/25/2011',
'3/17/2011',
'7/25/2011',
'10/19/2011' ]
7:14:27 AM Notice Execution completed
```

Move Row to Other Sheet Based on Cell Value

I have a sheet with rows I'd like to move to another sheet based on a cell value. I tried following this post's solution (refer below), but I'm having trouble editing the script towards what I want it to do.
I'm doing Check-Ins for an event. I would like to be able to change the value in Column F, populate Column G with the time the status changed, and for the row data to migrate to the Attendee Arrived sheet.
I believe the script already does this, but one has to run it manually. It also takes care of deleting the row data in A (Event) after migrating it to B (Attendee Arrived).
My question is could someone please help me set it up in order for script to run continuously (on edit), and also accomplish all of the above if I missed something?
I don't believe the script will respect the drop down format as it runs so I'm willing to manually type in something. It'd be cool if it could stay that way though - makes it easier for one.
Here's the sheet I'm testing on.
https://docs.google.com/spreadsheets/d/1HrFnV2gFKj1vkw_UpJN4tstHVPK6Y8XhHCIyna9TLJg/edit#gid=1517587380
Here's the solution I tried following. All credit to Jason P and Ritz for this.
Google App Script - Google Spreadsheets Move Row based on cell value efficiently
Thank you D:
function CheckIn() {
// How Many Columns over to copy
var columsCopyCount = 7; // A=1 B=2 C=3 ....
// What Column to Monitor
var columnsToMonitor = 6; // A=1 B=2 C=3 ....
//TARGET SPREAD SHEETS
var target1 = "Attendee Arrived";
//Target Value
var cellvalue = "Attendee Arrived";
//SOURCE SPREAD SHEET
var ss = SpreadsheetApp.openById('1HrFnV2gFKj1vkw_UpJN4tstHVPK6Y8XhHCIyna9TLJg');
var sourceSpreadSheetSheetID = ss.getSheetByName("Event");
var sourceSpreadSheetSheetID1 = ss.getSheetByName(target1);
var data = sourceSpreadSheetSheetID.getRange(2, 1, sourceSpreadSheetSheetID.getLastRow() - 1, sourceSpreadSheetSheetID.getLastColumn()).getValues();
var attendee = [];
for (var i = 0; i < data.length; i++) {
var rValue = data[i][6];
if (rValue == cellvalue) {
attendee.push(data[i]);
} else { //Fail Safe
attendee.push(data[i]);
}
}
if(attendee.length > 0){
sourceSpreadSheetSheetID1.getRange(sourceSpreadSheetSheetID1.getLastRow() + 1,
1, attendee.length, attendee[0].length).setValues(attendee);
}
//Will delete the rows of importdata once the data is copided to other
sheets
sourceSpreadSheetSheetID.deleteRows(2,
sourceSpreadSheetSheetID.getLastRow() - 1);
}
Try this:
I imagine that you already know that you'll need an installable onEdit Trigger and that you can't test a function of this nature by running it without the event object.
function checkIn(e) {
var sh=e.range.getSheet();
if(sh.getName()!="Event") return;
if(e.range.columnStart==6) {
if(e.value=="Attendee Arrived"){
e.range.offset(0,1).setValue(Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "M/d/yyyy HH:mm:ss"));
var row=sh.getRange(e.range.rowStart,1,1,sh.getLastColumn()).getValues()[0];
e.source.getSheetByName("Attendee Arrived").appendRow(row);
sh.deleteRow(e.range.rowStart);
}
}
}

Google Apps Scripts, onEdit function wont gets no value on edited range

I'm making a task manager in Google Sheets that when a task is created it sends the task that was just made to a target Sheet, I was able to get it to send the data just fine to the target sheet but my problem lies with what i wanted to do with that edit made on the target sheet. On the target sheet I want it to grab that info that was just inputted and place it in the next available row, but when I test my code It doesn't wanna work correctly.
My Code(for the target sheet):
function onEdit (e) {
var ss = SpreadsheetApp.openById('SheetIdHere');
var sheet = ss.getSheets()[0];
var sheetRows = sheet.getMaxRows();
var openRow = 0;
for (var i =4;i < sheetRows;i++) {
var currentValue = sheet.getRange(i,2).getValue();
if (currentValue == "") {
openRow = i;
break;
}
}
var lastEdit = sheet.getRange(1000, 2, 1, 3);
var lastEditValues = lastEdit.getValues();
var openRange = sheet.getRange(openRow, 2, 1, 3);
var openA1 = openRange.getA1Notation();
sheet.getRange(openA1).setValues(lastEditValues);
}
So far from my tests, the for loop to find the next available row is working fine because when I make another change on the sheet afterward it will grab the edited information fine and input it into the next row, but on the initial onEdit fire it will just grab the values from the previous test at row 1000 and put it into the next row instead of the new values.
I feel like there is a mistiming perhaps on when it grabs the values because if I clear the sheets and send a new task nothing appears on the next available row but I might be mistaken on that feeling.

JS / GS Simple Google Sheets Script

Im trying to create a simple script that firstly checks (all cells in row 3 starting from column 3) for whether they contain a name different from the available sheets and if so create a new one. If not go to the next cell down. Preferably until the row is empty but I didnt get that far. Currently I have
var row = 3; //Global Variable
function Main() { // Main Function
Activate();
GetNames();
}
function Activate() { // Initialize
var get = SpreadsheetApp.getActiveSpreadsheet();
var import = get.getSheetByName("Import");
}
function GetNames() { // Get Names and check for existing Sheets
var ss = SpreadsheetApp.getActiveSpreadsheet();
var import = ss.getSheetByName("Import");
var sheet = ss.getSheets()[0];
for (i = 0; i < 1000; i++) { // Loop which I think is broken
var names = import.getRange(row,3).getValue();
if (import.getSheetByName(names) == null) {
import.insertSheet(names);
import.activate();
}
row + 1;
}
}
And here is the Data
It succeeds to add the first sheet but fails to continue in the loop I think.
As you will probably see I'm very new to this and any help would be appreciated.
You probably wanted to increase row by 1 here:
row + 1;
But you're not. row + 1 is just an expression with a value (4, in your example, because row remains 3 throughout). What you would need is the statement
row = row + 1;
But if this is all that you're using the global variable row for, you don't need it at all. Just use the loop variable i that's already counting from 0 to 1000. You probably want something like import.getRange(i+3,3).

Categories

Resources