Trying to combine two working scripts does does not work - google-apps-script

I'm trying to make a quick macro to grab the current date and time and put it in a cell. I want to make this a static time. I made a quick macro by recording and it works as I recorded it, but when I ran the recorded macro it does nothing. I am just doing a now function and then copying it and pasting the value on top. If I split it into two separate macros, it works. I have no idea what I am doing wrong. Any help is appreciated.
"Timestamp" does not work.
"Now" works.
"copypaste" works.
'''
function TimeStamp() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getCurrentCell().setFormulaR1C1('=now()');
spreadsheet.getActiveRange().copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
};
function Now() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getCurrentCell().setFormulaR1C1('=now()');
};
function copypaste() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getActiveRange().copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
};
'''

You may use date object to return timestamp compared with using =now formula, which is faster and prevent script to skip your next line:
function TimeStamp() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getCurrentCell().setValue(new Date());
};
Reference
Get today date in google appScript
Edit: Original issue
In the original script, the script might not apply the changes after setting the formula =now() and before copy/paste, since spreadsheet operations are sometimes bundled together to improve performance. So it's treating the active range as empty, and after pasting this empty value, the cell will remain empty.
To avoid that, you could have used SpreadsheetApp.flush() after setting the formula =now().

Related

Trouble triggering a macro when a specific cell has a specific value

I'm trying to trigger a google sheet macro / apps script to reformat a sheet when a specific value is entered into a specific cell. I have been working on it to get it to work but without success.
Here is my code;
function onEdit(e) {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getRange('C2');
var cellContent = cell.getValue();
if(cellContent === 'Past campaigns - actual cashflows to date only') {
spreadsheet.getRange('7:12').activate();
spreadsheet.getActiveSheet().hideRows(spreadsheet.getActiveRange().getRow(), spreadsheet.getActiveRange().getNumRows());
spreadsheet.getRange('13:13').activate();
}
};
I'm new to macros and apps scripts. I have tried to implement all the suggestions from the following links without success;
How can I get a macro to automatically trigger when a cell reaches a certain value in a Google Sheet?
https://developers.google.com/apps-script/guides/triggers
https://developers.google.com/apps-script/guides/sheets
As #Cooper has said you cannot make a trigger based on a cell value. Only on user changes.
You could try to make the onEdit trigger to execute only inside an if statement. But that's already what you have done.
Try this:
function onEdit(e) {
e.source.toast('Entry');
const sh=e.range.getSheet();
if(sh.getName()!='Sheet Name')return;//you need to change this sheetname
const X=sh.getRange('C2').getValue();
if(X=='Past campaigns - actual cashflows to date only') {
e.source.toast('flag1');
sh.hideRows(e.range.rowStart,e.range.rowEnd-e.range.rowStart+1);
}
}
It's not necessary to use activate in most scripts and certainly in this one since it has to finish in 30 seconds. They use activate in macros because they are following you actions as you move around the screen. But in a script, generally to don't want to interact with the screen very much because it slows down the script and it doesn't really accomplish anything.
I'm currently using in a script that run when a Spreadsheet opens up because it has a lot rows in it and I want it to go down to the last row. So activate is useful because I don't have to scroll down to the last row every time I open the spreadsheet.
try it this way:
function onEdit(e) {
//e.source.toast('Entry');
var sh=e.range.getSheet();
if(sh.getName()!='Sheet Name')return;//you need to change this sheetnamee
var X=sh.getRange('C2').getValue();
if(X=='Past campaigns - actual cashflows to date only') {
//e.source.toast('flag1');
sh.hideRows(e.range.rowStart,e.range.rowEnd-e.range.rowStart+1);
}
}
I hope you're not trying to run this from the script editor because that's not going to work.

GOOGLE script 'copyTo values only' does not work when the source is a function (e.g. NOW())

I am trying to copy the values only from a cell containing the function NOW().
For everything I try the target cell is empty :-(
I have tried:
spreadsheet.getRange('K1').activate();
spreadsheet.getCurrentCell().setValue('Erstellt am:');
spreadsheet.getRange('P1').activate();
spreadsheet.getCurrentCell().setFormula('=NOW()');
spreadsheet.getRange('N1').activate();
spreadsheet.getRange('P1').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
spreadsheet.getActiveRangeList().setNumberFormat('dd.MM.yyyy HH:mm:ss');
The result is that cell N1 is empty. If I add the statement:
spreadsheet.getCurrentCell().setValue('OTTO');
Then the cell N1 gets the value OTTO as expected.
I also tried outsourcing the logic into a separate function like this:
function COPY_DATE() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('N1').activate();
spreadsheet.getRange('P1').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
spreadsheet.getActiveRangeList().setNumberFormat('dd.MM.yyyy HH:mm:ss');
};
This did not work either.
I also tried this way:
var source = spreadsheet.getRange ('P1');
source.copyTo (spreadsheet.getRange ('N1'), {contentsOnly:true});
Everything to no avail. I would really like to know what's going on here and appreciate any feedback.
To be honest, I have no idea why SpreadsheetApp.CopyPasteType.PASTE_VALUES isn't working here.
Instead of doing that, try a different approach: use getValue() and setValue().
spreadsheet.getRange('N1').setValue(spreadsheet.getRange('P1').getValue())
I'm not sure if it makes sense for your purposes, but I'd also suggest you look at removing a lot of those .activate() calls. As I wrote in this answer, activation is basically just for interacting with a user selection, and it can slow down the execution. The way you're doing it, you're calling the Spreadsheet service 4 times:
get the range
activate the range
get the activated range
do something to the activated ranged
You can halve those calls by simply getting the range and then perform whatever actions you need on it. Then you could simplify your code to something like this:
spreadsheet.getRange('K1').setValue('Erstellt am:');
var value = spreadsheet.getRange('P1').setFormula('=NOW()').getValue();
spreadsheet.getRange('N1').setValue(value).setNumberFormat('dd.MM.yyyy HH:mm:ss');
I tested the following code and is working perfect setting the date value from P1 cell to N1 cell:
function COPY_DATE() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('N2').activate();
spreadsheet.getRange('P1').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
spreadsheet.getActiveRangeList().setNumberFormat('dd.MM.yyyy HH:mm:ss');
};
Remember that to use getActive() type of functions you need to have the script bound to the Spreadsheet [1].
[1] https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#getactive

Writing into another Spreadsheet with SetValue fails without errors/exceptions

I'm trying to update a spreadsheet from a script running on another spreadsheet.
Nothing seems to have any effect on the table (SetValue(), SetBackgroundRGB(), etc.).
I've checked the scope, it includes "https://www.googleapis.com/auth/spreadsheets" permission; besides, this same script has no problem writing to another spreadsheet that it creates in runtime.
function updateAnotheSpreadsheet() {
var targetSpreadsheet = SpreadsheetApp.openById('<target spreadsheet id>');
var sheet = targetSpreadsheet.getSheetByName('<sheet name>');
Browser.msgBox(sheet.getRange("A1").getValue()); // Here I see that my getSheetByName worked
sheet.getRange("A1").setValue('Test value'); // But this does nothing
}
There are no errors but also no effect: nothing changes in the target spreadsheet.
Hi I was testing and was able to do what you are trying to do. You can try to declare a variable for the message, here is what I was able to do, I hope this resolves your inquiry.
function updateAnotherSpreadsheet() {
//Opening the second Spreadsheet by ID
var targetSpreadSheet = SpreadsheetApp.openById("<SpreadSheetId>");
var sheet = targetSpreadSheet.getSheetByName("<SheetName>");
//Getting the range to show on msgBox.
var msg = sheet.getRange("A1:A1").getValue();
//Displaying old data on A1:A1 from the secondary Spreadsheet.
Browser.msgBox("Old data on secondary spreadsheet: " + msg);
//Getting the range and setting new values
sheet.getRange("A1:A1").setValue('Test value').setBackground("teal").setFontColor("white");
}
I would suggest to check for more information here https://developers.google.com/apps-script/guides/sheets.
I hope this helps, greetings.
I found the problem.
A function called from OnEdit() can't ask for permissions. I needed to first update that other spreadsheet from any function called by something "active", like a button; then, after the script asks for permission once, it can do its thing from OnEdit() the next time it runs.

Pasting Values to Work as Folmula (Apps Script for Google Sheets)

I need to filter data from the latest sheet (a new one gets created every day automatically). The formula I use is
=FILTER('S&T 18/3/2019'!N:N;ISBLANK('S&T 18/3/2019'!N:N)=FALSE)
And it works, so in another cell I have´ve written another formula that keeps the first one up to date:
=CONCATENATE("=filter('S&T ";TEXT(TODAY();"d/m/yyyy");"'!N:N;ISBLANK('S&T";TEXT(TODAY();"d/m/yyyy");"'!N:N)=FALSE)")
In apps script I use the following code to paste the second formula as values, and it also works, but in its cell it shows as text instead of as a formula. If I manually delete the = form the beginning and then add it again it works perfectly. The idea is for it to work on its own. Can anyone help?
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Test Filtro'), true);
spreadsheet.getRange('D1').activate();
spreadsheet.getRange('D1').copyTo(spreadsheet.getRange('E2'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
spreadsheet.getRange('E2').activateAsCurrentCell();
The Range#copyTo method accepts 2 optional arguments, the CopyPasteType and whether the data should be transposed. Your code fails to copy as a formula, because you use the CopyPasteType enum PASTE_VALUES. To copy a formula, you should use PASTE_FORMULA.
Enum CopyPasteType
PASTE_NORMAL Enum Paste values, formulas, formats and merges.
PASTE_FORMULA Enum Paste the formulas only.
PASTE_VALUES Enum Paste the values ONLY without formats, formulas or merges.
Your code would then look like:
...
var destCell = spreadsheet.getRange("E2");
spreadsheet.getRange("D1").copyTo(destCell, SpreadsheetApp.CopyPasteType.PASTE_FORMULA, false);
destCell.activateAsCurrentCell();
...
Since you are trying to do a "double paste" (your source data is a formula that creates a formula when it is evaluated, and you want to write the created formula), you need to paste the value of the original cell, then re-copy the output (your desired formula) and paste it as a formula:
...
const AS = SpreadsheetApp.CopyPasteType;
var destCell = spreadsheet.getRange("E2");
spreadsheet.getRange("D1").copyTo(destCell, AS.PASTE_VALUES, false); // Compute the desired formula, via formula-to-value conversion.
SpreadsheetApp.flush(); // Force the first copy to occur.
destCell.copyTo(destCell, AS.PASTE_FORMULA, false); // Activate the computed formula.
destCell.activateAsCurrentCell();
...
You may be able to avoid the first range copy entirely, by constructing the formula in script.
...
var TODAY = Utilities.formatDate(new Date(), "your timezone", "your format string here");
var myFormula = "=FILTER('S&T " + TODAY + "'!N:N;ISBLANK('S&T " + TODAY + "'!N:N)=FALSE)";
destCell.setFormula(myFormula);
...
Utilities.formatDate

How can I get a macro to automatically trigger when a cell reaches a certain value in a Google Sheet?

What I need is for a macro I've recorded called SwitchHotSeat to trigger when the value of cell F3 goes above £1,000,000.00 0r 1000000 or the LEN of cell F3 goes over that length.
I can find guides for doing this in Excel, but not for Google Sheets. below is just the code for my macro.
function SwitchHotSeat() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('3:3').activate();
spreadsheet.getActiveSheet().deleteRows(spreadsheet.getActiveRange().getRow(), spreadsheet.getActiveRange().getNumRows());
spreadsheet.getActiveRangeList().setBackground('#ff0000')
.setFontColor('#ffffff');
};
The macro works fine. I just need a way of triggering it when that cell goes over the 1000000.
You could use simple or installable triggers. See
https://developers.google.com/apps-script/guides/triggers
https://developers.google.com/apps-script/guides/triggers/installable
Example of using onEdit simple trigger
function onEdit(e){
if(/* add here your conditions */) {
SwitchHotSeat();
}
}
NOTE: on edit and on change triggers are triggered only when an user edit the spreadsheet.
Just in case it helps anyone else with a similar issue, I discovered (by logging) that it was returning an object, rather than a number before, so the following code worked fine in the end.
function onFormSubmit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var millionaire24 = ss.getSheetByName('Millionaire24.');
var cellValue = millionaire24.getRange(3,6,1,1).getValues();
Number(cellValue)
if(cellValue[0] >= 1000000)switchHotSeat();
}