Google Sheets as Database - google-apps-script

I'm trying to enter some data on a sheet in google sheets create a button that submits data onto another sheet. The other sheet will be like my database.
I have little to no JS experience. I'm able to create the button and link it my script but after that, I'm lost. This code worked well to get data to my database sheet. The problem is that the data stays on the same row and when I run the script the old data is erased.
function transfer() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getSheets()[0];
var destination = ss.getSheets()[1];
var range1 = source.getRange("B2");
range2.copyValuesToRange(destination,3,3,2,2);
range2.clearContent();
var range2 = source.getRange("C2");
range2.copyValuesToRange(destination,4,4,2,2);
range2.clearContent();
var range3 = source.getRange("D2");
range3.copyValuesToRange(destination,5,5,2,2);
range3.clearContent();
var range4 = source.getRange("C2");
range4.copyValuesToRange(destination,4,4,2,2);
range4.clearContent();
}
The other issue is I don't want the cells to be empty so I tried to set an alert.
var range1 = source.getRange("A2");
range1.copyValuesToRange(destination,2,2,2,2);
if (range1 ==!"");
Browser.msgBox("Please Enter A Date");
It prompted the msg box but still copied the data over.
Last I would like range1 to be like a unique ID. So if I put a value in A2 on my source sheet then it will auto-fill the other cells.
Here's the link if that helps.
https://docs.google.com/spreadsheets/d/1Zi7Oc0f5AlxcRRoFMM1Q1VkkM1Co6Yo8yYBY1TvkQMc/edit?usp=sharing

I recommend that you spend more time with the documentation. Personally, I've never considered putting buttons directly on the spreadsheet. I'd rather use the menu or a dialog or a sidebar. Also you generally pick up a lot of performance to replace the use of getValue() with getValues() where appropriate.
But here's another way to approach the problem your working on. Perhaps it will give something to think about. Have fun. Your buttons do look nice though. Very nice work.
function onOpen(){//This will put a post button on a menu
SpreadsheetApp.getUi().createMenu('My Menu')
.addItem('Post Data', 'postData')
.addToUi();
}
function postData() {//this will append data fromm 'DataEntry' to 'DB' with a timestamp spliced into it.
var ss=SpreadsheetApp.getActive();
var sh1=ss.getSheetByName('DataEntry');
var sh2=ss.getSheetByName('DB');
var rg1=sh1.getRange(sh1.getLastRow(),1,1,sh1.getLastColumn());
var vA=rg1.getValues();
vA[0].splice(0,0,Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"E MMM dd, yyyy HH:mm:ss"));
sh2.appendRow(vA[0]);
}
This is what my DateEntry tab looks like:
This is what my DB tab looks like:
The post just adds the last row in DataEntry to the row after the last row in DB.

Related

Selected cell does not update when using button linked to script

I have a sheet for users to enter a cash-count and their initials then hit a button which runs a script and stores these inputs in a table.
The problem is, if the user types the information (e.g. their initials) and hits the button without first pressing Return or selecting another cell, the information is not saved.
I've seen a similar post:
How to force flush a user's input?
and tried the solutions, some don't work and none are really what I'm looking for. I know that I could use a Checkbox instead of a button but I'd like to find a way do it without resorting to that. The table is a cash-count for a till so not all cells require a value (there may be no $100 notes for example) and I won't know which was the last cell edited.
[The Data][1]
[1]: https://i.stack.imgur.com/mdKXk.png
The Code:
function Accept() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var db = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DATA");
var vals = db.getRange("B:B").getValues();
var last = vals.filter(String).length;
var ui = SpreadsheetApp.getUi();
var user = ui.prompt("Notes:");
var values = [[
sheet.getRange("I7").getValue(), //Date/Time
sheet.getRange("N16").getValue(), //Amount
sheet.getRange("E17").getValue(), //Initials
user.getResponseText(), //Notes
]];
db.getRange(last+1,2,1,4).setValues(values);
}
One solution is to utilize a checkbox as the Accept button, and use an onEdit(e) simple trigger to run your Accept() function.
See the checkboxButtons_ script for sample code.

Google sheets appscript to copy tabs to new sheets

I have a google sheet with around 190 tabs on that i need to split into 190 different files
The files need to be named the same as the tab, the contents of the tab need to be copied as values but i also need to bring the formatting accross (just not the formulas).
I have looked around, and through a combination of previous questions and answers plus using the function list help have formed the following code. It actually works for the first few tabs but then throws up an error about being unable to delete the only sheet.
function copySheetsToSS() {
var ss = SpreadsheetApp.getActive();
for(var n in ss.getSheets()){
var sheet = ss.getSheets()[n];// look at every sheet in spreadsheet
var name = sheet.getName();//get name
if(name != 'master' && name != 'test'){ // exclude some names
var alreadyExist = DriveApp.getFilesByName(name);// check if already there
while(alreadyExist.hasNext()){
alreadyExist.next().setTrashed(true);// delete all files with this name
}
var copy = SpreadsheetApp.create(name);// create the copy
sheet.copyTo(copy);
copy.deleteSheet(copy.getSheets()[0]);// remove original "Sheet1"
copy.getSheets()[0].setName(name);// rename first sheet to same name as SS
var target_sheet = copy.getSheetByName(name);
var source_range = sheet.getRange("A1:M50");
var target_range = target_sheet.getRange("A1:M50");
var values = source_range.getValues();
target_range.setValues(values);
}
}
}
I am hoping someone can tell me what i have done wrong as I cannot figure it out at this point. I am also open to better solutions though please be aware I am very much a beginner on google appscript, nothing too complex please.
thankyou
In principle your script correctly adds a new sheet to the new spreadsheet before removing the preexisting one
However, mind that calls to service such as SpreadsheetApp are asynchronous.
And this becomes the more noticeable, the longer your script runs.
In your case it apparently leads to behavior that the only sheet is being deleted before the new sheet is being created.
To avoid this, you can force the execution to be synchronous by implementing calls to SpreadsheetApp.flush().
This will ensure that the old sheet won't be deleted before the new one gets inserted.
Sample:
copy.deleteSheet(copy.getSheets()[0]);// remove original "Sheet1"
SpreadsheetApp.flush();
copy.getSheets()[0].setName(name);
You might want to introduce call toflush()` also at other positions where it is important for the code to run synchronously.

Google Sheets Macro not completing

I'm trying to parse a CSV file using Google Sheets macros. I've recorded all the steps as individual macros, and one by one they work fine, but when I combine into one macro, it doesn't run properly. The point at which it stops working is after the PODdateformatting part has completed and it's run through the first three lines of Daystodeliverformula. Cell H2 is populated with the formula, but the formula doesn't then autofill down the rest of the column. Any ideas? Or indeed, am I going about this all wrong and need a good talking to? :-)
function TheWholeShebang() {
var spreadsheet = SpreadsheetApp.getActive(); // start of DeletedUnwantedColumns
spreadsheet.getRange('AA:DE').activate();
spreadsheet.getActiveSheet().deleteColumns(spreadsheet.getActiveRange().getColumn(), spreadsheet.getActiveRange().getNumColumns());
spreadsheet.getRange('W:X').activate();
spreadsheet.getActiveSheet().deleteColumns(spreadsheet.getActiveRange().getColumn(), spreadsheet.getActiveRange().getNumColumns());
spreadsheet.getRange('R:U').activate();
spreadsheet.getActiveSheet().deleteColumns(spreadsheet.getActiveRange().getColumn(), spreadsheet.getActiveRange().getNumColumns());
spreadsheet.getRange('H:P').activate();
spreadsheet.setCurrentCell(spreadsheet.getRange('P1'));
spreadsheet.getActiveSheet().deleteColumns(spreadsheet.getActiveRange().getColumn(), spreadsheet.getActiveRange().getNumColumns());
spreadsheet.getRange('A:E').activate();
spreadsheet.setCurrentCell(spreadsheet.getRange('E1'));
spreadsheet.getActiveSheet().deleteColumns(spreadsheet.getActiveRange().getColumn(), spreadsheet.getActiveRange().getNumColumns()); // end of DeletedUnwantedColumns
var spreadsheet = SpreadsheetApp.getActive(); // start of Addcolumnsandheaderlabels
spreadsheet.getRange('A:F').activate();
spreadsheet.getActiveSheet().insertColumnsAfter(spreadsheet.getActiveRange().getLastColumn(), 6);
spreadsheet.getActiveRange().offset(0, spreadsheet.getActiveRange().getNumColumns(), spreadsheet.getActiveRange().getNumRows(), 6).activate();
spreadsheet.getRange('G1').activate();
spreadsheet.getCurrentCell().setValue('POD Date (formatted)');
spreadsheet.getRange('H1').activate();
spreadsheet.getCurrentCell().setValue('Days to Deliver');
spreadsheet.getRange('G2').activate(); // end of Addcolumnsandheaderlabels
var spreadsheet = SpreadsheetApp.getActive(); // start of PODdateformatting
spreadsheet.getRange('G2').activate()
.setFormula('=DATE(LEFT(D2,4),mid(D2,5,2),right(D2,2))');
spreadsheet.getActiveRange().autoFillToNeighbor(SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES); // end of PODdateformatting
var spreadsheet = SpreadsheetApp.getActive(); //start of Daystodeliverformula
spreadsheet.getRange('H2').activate()
.setFormula('=NETWORKDAYS(E2,G2,Instructions!$B$15:$B$40)-1');
spreadsheet.getActiveRange().autoFillToNeighbor(SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES); // end of Daystodeliverformula
};
After messing about with range.autoFillToNeighbor() and failing (see comments above) I was still suspicious about that method.
When I used this the range.autoFill() method instead it all worked fine. See code below.
// start of PODdateformatting
//var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('G2').activate().setFormula('=DATE(LEFT(D2,4),mid(D2,5,2),right(D2,2))');
var sourceRange = spreadsheet.getRange("G2:G2");
var destination = spreadsheet.getRange("G2:G369");
sourceRange.autoFill(destination,SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
//start of Daystodeliverformula
var spreadsheet = SpreadsheetApp.getActive();
var range = spreadsheet.getRange('H2').activate().setFormula('=NETWORKDAYS(E2,G2,Instructions!$B$15:$B$40)-1');
var sourceRange = spreadsheet.getRange("H2:H2");
var destination = spreadsheet.getRange("H2:H369");
sourceRange.autoFill(destination,SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
In hindsight I now believe that range.autoFillToNeighbor() was never right for your use case in the first place!
range.autoFillToNeighbor() expects to build autofill formulas based on data that is contained in neighbouring columns. It tries to do this intelligently, but neighbouring columns do not contain anything useful! Its amazing it ever worked... maybe sometimes defaulting to range.autoFill()!
range.autoFill() on the other hand, just duplicates the formula (data) above or below ( NOT looking to neighbouring cells for help).
You can copy and paste these over the corresponding functions in function TheWholeShebang() and should all work.
Note I assume a fixed range of 369 as per your data, but you can calculate this based on actual size if you prefer, in case no of rows is changed.

How to create a button which clears data in spreadsheets

Currently I have a google spreadsheet document in which users are inputting data based on conditional formatting the cells are changing colors. I would like to create a button with which I can easy restore all the cells into their first state.
I have this script at the moment:
function clearRange() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
sheet.getRange('B13:B30').clearContent();
}
Which works like a charm but the thing is that I have default data in the cells and when this scripts get applied it clears the default data.
Any ideas how to make such a script which will clear only the inputted data by the user.
It's not the solution you want but apart from what Scott suggested, which is the most straightforward approach, you could make a copy of your sheet in the unedited state. In this copy have a script which will just copy and paste the info into the sheet that the user fills in.
Then if you make changes you just need to update the template sheet and not the script.
This is a very basic script but should you'll get the idea.
function myFunction() {
var app = SpreadsheetApp;
var tempSheet = app.getActiveSpreadsheet().getSheetByName('Sheet1');
var inputSheet = app.openById('-----ID OF INPUT SHEET----').getSheetByName('Sheet1');
var tempData = tempSheet.getDataRange().getValues();
inputSheet.getRange(1, 1, tempData.length,
tempData[1].length).setValues(tempData);
}

Google Sheets script to copy/paste from one sheet to another

Could someone help me with creating a script that does the following:
Function: Upon adding a new sheet to my already existing workbook, I would like it to copy Column "E" from Sheet 1 and (Paste Special > Conditional formatting only) to the newly introduced Sheet "X"
Where can I learn more on how to write code? I have never used Stackoverflow by the way someone just recommended me to come here. I believe I just answered my own question somehow on the post, which I am sure was wrong to do but I couldn't comment on an already existing answer without exceeding the limit.
// Adds custom menu
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('CustomMenu').addItem('Copy format', 'copyFormat') //Add function to menu.'GIVE NAME HERE', 'functionName'
.addToUi();
}
function copyFormat() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh1 = ss.getSheets()[0]; //Gets the first sheet of the workbook. Can use ss.getSheetByName('Name of sheet here'); If it is not the first sheet
var activeSh = ss.getActiveSheet(); //Get the active sheet, you should be on the sheet just added
var rowEnd = activeSh.getLastRow(); //Last row of active sheet
sh1.getRange("E1:E").copyFormatToRange(activeSh, 5, 5, 1, rowEnd); //Copy format, including conditional, to column E of active sheet
}
This just adds a button that allows you to select a cell and give it the same conditions has in the original sheet.
Example: Sheet 1: Column E1:E100 has a given condition.. which needs to apply in the exact same way to any new incoming sheets since they all come in the same format. Right now its at a point of which when a new sheet arrives in the workbook: I can enter the new sheet > Select the cell which requires the conditions > Select the custom menu > Cell gets conditioned. So the next step would be automate the process I just mentioned since there is several sheets added daily to the workbook.