Spreadsheets to calendar depending on the decision of an operator - google-apps-script

Hello I am making a script that takes data from a worksheet (which receives data from a form) creates an event in my main calendar depending on the decision of an operator.
It receives the data from the form in columns A through F. In column G the operator decides whether to "Yes" or "No".
If G is "Yes" the script checks in column H if something is written. If it is empty
The script writes to column H and creates an event with the data of A: F,
If not something is written in column H it simply passes to the next line until the last one is written.
My script works correctly only if the entire H column is empty. This forces me to always clear column H and duplicate events already written to the calendar with each new entry.
How do I get the script to continue running without having to clear the H column?
My script is:
function teste() {
var ss = SpreadsheetApp.getActive();
var dados = ss.getDataRange().getValues();
var ultimaLinha = ss.getLastRow() - 1;
var options = {
description: dados[ultimaLinha][2],
location: dados[ultimaLinha][5],
};
for (var i = 1; i < ultimaLinha + 1; i++) {
var validacao = dados[i][6];
var escrita = dados[i][7];
if (validacao === "Yes") {
if (escrita == null) {
SpreadsheetApp.getActiveSheet().getRange(i + 1, 8).setValue('ok');
var event = CalendarApp.getDefaultCalendar().createEvent(
dados[i][1],
new Date(dados[i][3]),
new Date(dados[i][4]),
options);
}
}
}
My worksheet

When you getValues() the empty cells in the data array still exist, they just contain an empty string. Change null to ""
if (escrita == "") {
...
}

If I understand your summary correctly, I think you need to remove the following check.
if (escrita == null) {

Related

How to modify Apps Script for Google Sheets to move specific cell from a row into another Sheet

The script, that I will post below, allows me to use a check box to move an entire row from one sheet to another in the same workbook. Everything works (I was following a YouTube tutorial), but it moves the entire row of data. Instead, I need it to move only data from specific columns, i.e. move the info from column A to C or move the info from column A and column K. I know this might be a simple question, but I just don't know which line to modify and how to modify it so that the script only pulls the info from specific columns within the row to move to the other sheet.
function sendMail() {
var client = 3;
var date = 0;
var email = 19;
var dnr = 18;
var emailTemp = HtmlService.createTemplateFromFile("email");
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Promos");
var data = ws.getRange("A3:T" + ws.getLastRow()).getValues();
data = data.filter(function(r){return r[1] == true })
data.forEach(function(row){
emailTemp.client = row[client];
emailTemp.date = row[date];
emailTemp.dnr = row[dnr];
var htmlMessage = emailTemp.evaluate().getContent();
GmailApp.sendEmail(row[email],
"Promo Reminder",
"Your email does not support html",
{name: "JV Ops", htmlBody: htmlMessage}
);
});
}
I tried to modify the line "var row = range.getRow()" by putting column letters in the parenthesis but it didn't do anything, not only did it not move the info from those specific columns but it no longer moved the entire row. It just no longer did anything.
You have a spreadsheet in which a "checked" checkbox identified the row(s) that are to be sent an email. However you can't identify the actual row number of the checked checkbox.
There are two issues in your script:
data = data.filter(function(r){return r[1] == true }) replaces the array that contains ALL the data on the sheet with just those rows that contain checked checkboxes.
you need to compare the new filtered array with the original array in order to get the row numbers. I adapted the method described in StackOverflow compare rows on google spreadsheets
the array equalRows contains the row numbers/indexes that contain checked checkboxes.
the OP can use the row number together with the mailData array to copy data on the relevant row.
function myFunction() {
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Promos")
var data = ws.getRange("A3:T" + ws.getLastRow()).getValues();
// Logger.log(data) // DEBUG
var mailData = data.filter(function(r){return r[1] == true })
// Logger.log(mailData) // DEBUG
// compare rows on google spreadsheets
// https://stackoverflow.com/a/34960630/1330560
var equalRows = [];
for(var i in data){
var anEqualRow = false;
for(var j in mailData){
if(data[i].join() == mailData[j].join()){
anEqualRow = true;
}
}
if(anEqualRow){
var row = +i+3
equalRows.push(row);
}
}
// Logger.log(equalRows) // DEBUG
}

Google Apps Script - Conditionally retrieve data from other Google Sheet to Overview sheet

To explain the larger context: there are several forms which generate different sheets. I'm looking for a way to conditionally copy some of the responses sheet to a seperate "Overview" document. Code-wise, I had some ideas for the Overview document, but stranded near the start.
My method was going to be to build functions for all the information I want to retrieve, such as date of birth (example in code block below), date of submission and phone number, when I click on a button. The information may only be copied if the first and surname match the ones in the Overview. The order of the sheets in different docs are not the same and the column length is continually in flux. Furthermore, the amount of rows in the Overview doc is different than the form submission sheets.
In other words: if Anne Annenson would be the twenty-first respondent to a form, I want that information in the overview sheet where they are the first person.
function getDobs() {
var targetSpreadsheet = SpreadsheetApp.getActive();
var targetSheet = targetSpreadsheet.getSheetByName("Overview");
var targetFirstNameCheck = targetSpreadsheet.getRange("A4:A");
var targetSurnameCheck = targetSpreadsheet.getRange("B4:B");
var sourceSpreadsheetDob = SpreadsheetApp.openById("...");
var sourceDob = sourceSpreadsheetDob.getSheetByName("Form responses 1");
var sourceFirstNameCheckDob = sourceSheetDob.getRange("C2:C");
var sourceSurnameCheckDob = sourceSheetDob.getRange("D2:D");
var sourceRangeDob = sourceSheetDobConsent.getRange("E2:E");
if (sourceFirstNameCheckDob==targetFirstNameCheck && sourceSurnameCheckDob==targetSurnameCheck){ //then I want to copy the data
var sourceData = sourceRangePronouns.getValues();
var targetRangeDob = targetSheet.getRange("C4:C");
}
else (//I want it to leave the cells alone, so any text or formatting that might have been put in manually is still there.){
}
}
I would like for the responses to remain in the form response sheets as well.
Any thoughts?
Cooper already explained all the things you need in the comments. And below is what your code would look like following Cooper's comments.
Code
function getDobs() {
var targetSpreadsheet = SpreadsheetApp.getActive();
var targetSheet = targetSpreadsheet.getSheetByName("Overview");
var targetLastRow = targetSheet.getLastRow();
// range equivalent to A4:B
var targetNamesCheck = targetSheet.getRange(4, 1, targetLastRow - 3, 2).getValues();
// tested in same spreadsheet, change "targetSpreadsheet" to openById on your actual script
var sourceSpreadsheetDob = targetSpreadsheet;
var sourceDob = sourceSpreadsheetDob.getSheetByName("Form responses 1");
var sourceLastRow = sourceDob.getLastRow();
// range equivalent to C2:D
var sourceNamesCheckDob = sourceDob.getRange(2, 3, sourceLastRow - 1, 2).getValues();
// range for data to be copied (E2:G in my sample data)
var sourceRangeDob = sourceDob.getRange(2, 5, sourceLastRow - 1, 3).getValues();
var output = [];
targetNamesCheck.forEach(function (targetNames) {
// search sourceNamesCheckDob for targetNames
var index = searchForArray(sourceNamesCheckDob, targetNames);
// if targetNames is in sourceNamesCheckDob, save the data on that row for later
if (index > -1)
output.push(sourceRangeDob[index]);
// append blank cells if data is not found
else
output.push(new Array(sourceRangeDob[0].length));
});
// if there were names that were found, write the data beside the targetNames
if (output.length > 0) {
targetSheet.getRange(4, 3, output.length, output[0].length).setValues(output);
}
}
// function to search the array for the object
function searchForArray(haystack, needle) {
var i, j, current;
for(i = 0; i < haystack.length; ++i) {
if(needle.length === haystack[i].length) {
current = haystack[i];
for(j = 0; j < needle.length && needle[j] === current[j]; ++j);
if(j === needle.length)
return i;
}
}
return -1;
}
Overview:
Form responses 1:
Overview after running getDobs:
EDIT:
Since there are no methods that includes the apostrophe when the cell value is being fetched, easiest way is to have the sheets identify the phone number as text so it won't remove the 0 in the beginning. I've thought of 3 ways to have the 0 included in the output:
Add the apostrophe manually on the specific output column via script
Add dashes on the number so it is treated as text (09395398314 -> 093-9539-8314) (just an example, not sure if that is the right format)
Format the output column into number -> plain text instead of number -> automatic
I prefer formatting the output column as that will be the fastest and easiest thing to do.
Format:
Output:
Note:
This function will fill up rows where names in Overview are present in Form responses 1.
References:
Check whether an array exists in an array of arrays?
javascript create empty array of a given size

Apps Script: Check if range is empty and copy data

I'm trying to build an automated list with google sheets. The first sheet(A) is for input of production data of a week. The second sheet(B) should be the data archive. Thus i want the content from sheet A copied to sheet B and then deleted in sheet a. It should be copied in the next empty range in sheet B.
My problem must be inside the notation of the "while" or / and the "if" but nothing seems to work properly.
The while checks if sheet A is already emptied, if not the "if" function checks a specific range in sheet B if it is empty. If thats the case it should be copying the data and then delete it. Else the column of the range in sheet b is changed to the next range (spaltennummer + 6).
While troubleshooting it either stays in the while (finds no empty range?) or it runs through without any effect. I tried "== 0", "== """, isblank and so on. (every option available?). Google didnt seem able to provide me an answer...
Thanks for ur help.
Code:
function myFunction() {}
function leerzelle(){
var spaltennummer = 4;
var rangeDatenarchiv = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Tabellenblatt1").getRange(8,spaltennummer,15,5);
var rangeDateneingabe = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Dateneingabe").getRange("J8:N22");
var values = rangeDateneingabe.getValues();
while(rangeDateneingabe !== 0){
if(rangeDatenarchiv == 0) {
rangeDatenarchiv.setValues(values);
rangeDateneingabe.setValues("");
}
else{
spaltennummer = spaltennummer + 6;
}
}
}
Try this:
Code:
function leerzelle() {
var spaltennummer = 4;
// Data entry
var rangeDateneingabe = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Dateneingabe").getRange("J8:N22");
var values = rangeDateneingabe.getValues();
// While we have value in data entry sheet
while (!rangeDateneingabe.isBlank()) {
// Update archive everytime you increment in else
var rangeDatenarchiv = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Tabellenblatt1").getRange(8, spaltennummer, 15, 5);
// If archive range is blank, move values
if (rangeDatenarchiv.isBlank()) {
rangeDatenarchiv.setValues(values);
rangeDateneingabe.clearContent();
}
else {
spaltennummer = spaltennummer + 6;
}
}
}
Note:
You just can't compare a range to a number, use isBlank to check if it doesn't have values instead.
You can't use setValues("") on a range to remove the contents, use clearContent instead to delete those values.
You need to redeclare archive range everytime you loop using the incremented column number
References:
isBlank
clearContent

Absolute reference with UDF & filtering data in google sheets script

Hi I am begineer to scripts, here is the code and googlesheet for reference
What i am getting
what i want to achieve
/**
*#param quest1 Question of the note
*#param quest1 Answer of the note
*#customfunction*/
function DMNOTE(quest1,ans1,quest2,ans2,quest3,ans3,) {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var result = quest1+'-'+ans1+','+quest2+'-'+ans2+','+quest3+'-'+ans3;
return result;
}
I want to achieve absolute reference for "quest" parameter and i want it to loop for rest of the coulmns till column where i enter the function.Also under "Formula Required" column i have put formla for reference thats how i want my UDF to work.
Follwing up i need to filter "Non-solicit agreement" and keep only "No" under it and Copy & Paste all colums highlited in blue to update tab.
function toFilter (){
// filter and retain "no" in non-solicit agreement
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Worksheet");
ss.getRange(1,1,ss.getLastRow(),ss.getLastColumn());
var createfilter = SpreadsheetApp.newFilterCriteria().setHiddenValues("Yes").build();
ss.getFilter().setColumnFilterCriteria(8, createfilter);
}
Hope i make sense. Any help is appriciated
To work with any number of arguments, you can have a function like below in your script
function DMNOTE(...arg){
let result = ''
for(let i=0;i<arg.length;i++){
result += `${arg[i]}-${arg[i+1]},`
i++;
}
return result.substring(0, result.length - 1);
}
And then form your spreadsheet you can call as =DMNOTE(A$1,A2,B$1,B2,C$1,C2) or =DMNOTE(A$1,A2,B$1,B2,C$1,C2,D$1,D2) The function will process all the arguments being passed and returns the result.
How to filter "non-solicit agreement" and take only data which has "no"
The code you provided comes already very close to what you desire, you just need to make the following adjustments:
setHiddenValues() expect an array, no a string, so change "Yes" to ["Yes"]
getFilter() only works to modify a filter that is present in the sheet already, in case there is none, it is better to delete the old filter and create a new one:
function toFilter(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Worksheet");
ss.getRange(1,1,ss.getLastRow(),ss.getLastColumn());
var createfilter = SpreadsheetApp.newFilterCriteria().setHiddenValues(["Yes"]).build();
if(ss.getFilter() != null) {
ss.getFilter().remove();
}
ss.getDataRange().createFilter().setColumnFilterCriteria(8, createfilter);
}
How to Copy & Paste all columns highlited in blue to update tab
Build a function that
calls toFilter()
checks for all rows either they are hidden
copies the non- hidden rows into an array
pastes this array to the sheet Update
function copyIfNotHidden(){
toFilter();
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = spreadsheet.getSheetByName("Worksheet");
var sheet2 = spreadsheet.getSheetByName("Update");
var data = sheet1.getDataRange().getValues();
var array = [];
for (var i = 0; i < data.length; i++){
if(sheet1.isRowHiddenByFilter(i+1)==false){
array.push(data[i]);
}
}
sheet2.getRange(sheet2.getLastRow()+1, 1, array.length, array[0].length).setValues(array);
}

Vlookup or Indexing using google apps scripts

I have a spreadshseet (Sheet1) in which the Data is there from Col A to Column D, and in another sheet (Sheet1), again the data is there from Col A to Col W, in which the Col F data has some matching with column D.
What i am seeking for:
I want to pull data from Sheet2 (from Col F onwards, i.e. G, H, I etc.) in Col E and so on in Sheet1.
Sheet2
Col
F G H I J K L
1 A B C D E F
2 a1 b1 c1 d1 e1 f1
3 a2 b2 c2 d2 e2 f2
and so on
Sheet1
Col D E F G H
1 A B C D
3 a2 b2 c2 d2
Data to reflect in col E,F,G H in sheet1 from sheet2 against column D in col E,F, either using vlookup, or indexing.
What i tried but in Vain
http://productforums.google.com/forum/#!topic/apps-script/HzeNdIqnIUc
I want to use only google apps only to get the desired results.
Requesting for help on this.
Regards
I'm sorry you're having a problem with your VLOOKUP but it's a Google Spreadsheets user question not a stackoverflow (programming) question. It might help you to know these things:
You're on the right track with VLOOKUP. The spreadsheet function VLOOKUP definitely works for getting data in sheet2 to lookup based on keys/columns in sheet1. It works really well for what you say you need to do.
You can search the Google support site: http://support.google.com/docs/bin/search.py?query=vlookup
You can ask in the Google Docs Help forum https://productforums.google.com/forum/#!forum/docs
Good luck.
Its an old article but others may still stumble across it.
Here is something I wrote to address my Vlookup Needs in script form.
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//--//Dependent on isEmpty_()
// Script Look-up
/*
Benefit of this script is:
-That google sheets will not continually do lookups on data that is not changing with using this function as it is set with hard values until script is kicked off again.
-Unlike Vlookup you can have it look at for reference data at any Column in the row. Does not have to be in the first column for it to work like Vlookup.
-You can return the Lookup to Memory for further processing by other functions
Useage:
var LocNum = SpreadsheetApp.openById(SheetID).getSheetByName('Sheet1').getRange('J2:J').getValues();
Lookup_(Sheetinfo,"Sheet1!A:B",0,[1],"Sheet1!I1","n","y");
//or
Lookup_(Sheetinfo,"Sheet1!A:B",0,[1],"return","n","n");
//or
Lookup_(Sheetinfo,"Sheet1!A:B",0,[0,1],"return","n","n");
//or
Lookup_(Sheetinfo,"Sheet1!A:B",1,[0],"return","y","n");
//or
Lookup_(Sheetinfo,"Sheet1!A:G",4,[0],"Database!A1","y","y");
*/
function Lookup_(Search_Key,RefSheetRange,SearchKey_Ref_IndexOffSet,IndexOffSetForReturn,SetSheetRange,ReturnMultiResults,Add_Note)
{
var RefSheetRange = RefSheetRange.split("!");
var Ref_Sheet = RefSheetRange[0];
var Ref_Range = RefSheetRange[1];
if(!/return/i.test(SetSheetRange))
{
var SetSheetRange = SetSheetRange.split("!");
var Set_Sheet = SetSheetRange[0];
var Set_Range = SetSheetRange[1];
var RowVal = SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(Set_Range).getRow();
var ColVal = SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(Set_Range).getColumn();
}
var twoDimensionalArray = [];
var data = SpreadsheetApp.getActive().getSheetByName(Ref_Sheet).getRange(Ref_Range).getValues(); //Syncs sheet by name and range into var
for (var i = 0, Il=Search_Key.length; i<Il; i++) // i = number of rows to index and search
{
var Sending = []; //Making a Blank Array
var newArray = []; //Making a Blank Array
var Found ="";
for (var nn=0, NNL=data.length; nn<NNL; nn++) //nn = will be the number of row that the data is found at
{
if(Found==1 && ReturnMultiResults.toUpperCase() == 'N') //if statement for found if found = 1 it will to stop all other logic in nn loop from running
{
break; //Breaking nn loop once found
}
if (data[nn][SearchKey_Ref_IndexOffSet]==Search_Key[i]) //if statement is triggered when the search_key is found.
{
var newArray = [];
for (var cc=0, CCL=IndexOffSetForReturn.length; cc<CCL; cc++) //cc = numbers of columns to referance
{
var iosr = IndexOffSetForReturn[cc]; //Loading the value of current cc
var Sending = data[nn][iosr]; //Loading data of Level nn offset by value of cc
if(isEmpty_(Sending)) //if statement for if one of the returned Column level cells are blank
{
var Sending = "#N/A"; //Sets #N/A on all column levels that are blank
}
if (CCL>1) //if statement for multi-Column returns
{
newArray.push(Sending);
if(CCL-1 == cc) //if statement for pulling all columns into larger array
{
twoDimensionalArray.push(newArray);
var Found = 1; //Modifying found to 1 if found to stop all other logic in nn loop
break; //Breaking cc loop once found
}
}
else if (CCL<=1) //if statement for single-Column returns
{
twoDimensionalArray.push(Sending);
var Found = 1; //Modifying found to 1 if found to stop all other logic in nn loop
break; //Breaking cc loop once found
}
}
}
if(NNL-1==nn && isEmpty_(Sending)) //following if statement is for if the current item in lookup array is not found. Nessessary for data structure.
{
for(var na=0,NAL=IndexOffSetForReturn.length;na<NAL;na++) //looping for the number of columns to place "#N/A" in to preserve data structure
{
if (NAL<=1) //checks to see if it's a single column return
{
var Sending = "#N/A";
twoDimensionalArray.push(Sending);
}
else if (NAL>1) //checks to see if it's a Multi column return
{
var Sending = "#N/A";
newArray.push(Sending);
}
}
if (NAL>1) //checks to see if it's a Multi column return
{
twoDimensionalArray.push(newArray);
}
}
}
}
if (CCL<=1) //checks to see if it's a single column return for running setValue
{
var singleArrayForm = [];
for (var l = 0,lL=twoDimensionalArray.length; l<lL; l++) //Builds 2d Looping-Array to allow choosing of columns at a future point
{
singleArrayForm.push([twoDimensionalArray[l]]);
}
if(!/return/i.test(SetSheetRange))
{
SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,singleArrayForm.length,singleArrayForm[0].length).setValues(singleArrayForm);
SpreadsheetApp.flush();
if(/y/i.test(Add_Note))
{
SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,1,1).setNote("VLookup Script Ran On: " + Utilities.formatDate(new Date(), "PST", "MM-dd-yyyy hh:mm a") + "\nRange: " + Ref_Sheet + "!" + Ref_Range);
}
}
else
{
return singleArrayForm
}
}
if (CCL>1) //checks to see if it's a multi column return for running setValues
{
if(!/return/i.test(SetSheetRange))
{
SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,twoDimensionalArray.length,twoDimensionalArray[0].length).setValues(twoDimensionalArray);
SpreadsheetApp.flush();
if(/y/i.test(Add_Note))
{
SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,1,1).setNote("VLookup Script Ran On: " + Utilities.formatDate(new Date(), "PST", "MM-dd-yyyy hh:mm a") + "\nRange: " + Ref_Sheet + "!" + Ref_Range);
}
}
else
{
return twoDimensionalArray
}
}
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
// Empty String Check
function isEmpty_(string)
{
if(Object.prototype.toString.call(string) == '[object Boolean]') return false;
if(!string) return true;
if(string == '') return true;
if(string === false) return true;
if(string === null) return true;
if(string == undefined) return true;
string = string+' '; // check for a bunch of whitespace
if('' == (string.replace(/^\s\s*/, '').replace(/\s\s*$/, ''))) return true;
return false;
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`