getCurrentCell Value from SpreadsheetApp opened by Id - javascript

I'm new to apps script.
I'm developing a ticketing system that, from a form responses, automatically creates new spreadsheets with the right ticket on it.
It works like a charm but I'm now having a problem...
I just want to know why, even if I activate the sheet opened by id, the function getCurrentCell() always return me the cell A1,
even if I have a different cell selected.
This is the simple function:
function getValue() {
var sheet = SpreadsheetApp.openById(id="").getSheetByName("Open Tickets").activate();
var cell = sheet.getCurrentCell().getValue().toString();
Logger.log(cell)
}
Thanks

Related

Container-bound Apps Script does not execute properly from change to Google Sheet under certain circumstances

I have a container-bound script that reads data from a Google Sheet (its container), creates an event in a Google Calendar and then updates the Google Sheet with a confirmation to say that it has created a calendar event. The script is triggered to execute every time there is a change to the spreadsheet.
During testing, the script works perfectly as it should. However, when data is automatically entered into the Google Sheet from a Google Form (followed by some changes made through a Google Forms add-on), the script executes but does not update the Sheet with the confirmation of a new calendar event. This then results in the script creating duplicate calendar events because it does not see the confirmation in the Google Sheet.
Here is an excerpt of my Google Sheet data:
Google Sheet data for employee leave details
And below is my script:
function synctocalendar() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
var calendarId = spreadsheet.getRange("Calendar_sync!H2").getValue();
var eventCal = CalendarApp.getCalendarById(calendarId);
var submissions = spreadsheet.getRange("Calendar_sync!A2:F").getValues();
var last = submissions.length-1
for (x=last; x>0; x--) {
var shift = submissions[x];
var startTime = shift[2];
var endTime = shift[3];
var title = shift[0]+" | "+shift[1];
var ssr = x+2
if (shift[4]!=="" && shift[4]!=="Complete" && shift[4]!=="Declined" && shift[4]!=="In progress") {
break
} else if (shift[4]=="Complete" && shift[5]!=="Y" && shift[5]!=="N") {
eventCal.createEvent(title, startTime, endTime);
var endf = spreadsheet.getRange(ssr,6)
endf.setValue("Y")
break
}
}
}
When I run the script directly from the editor it works perfectly. It reads the data, creates a calendar event, then returns a "Y" in column F (provided it satisfies the IF criteria).
When I have a trigger set to run the script whenever a change is made to the sheet, I can again get the script to run as I expect by manually deleting the "Y" from column F in any one of the rows.
However, when a new submission is written to the Google Sheet from a Google Form (followed by some spreadsheet changes made from a Google Forms add-on for approvals), the script still runs and still creates a calendar event, but does not write a "Y" back into the sheet.
EDIT: Details on the Google Forms add-on
The add-on sends emails on form submission with the form data to be approved. Once the recipient of the email approves the data from the Google Form, the add-on makes changes to the spreadsheet to reflect that.
i.e. when a form is submitted, column E in the spreadsheet will say "In Progress" and once the approval process is complete, the add-on will change column E to say "Complete". At this point, the script recognises it is complete and creates a calendar event.

Open two urls with one click

I'm new to Google Sheets and Apps Script. I have a sheet with two URLS. In cell F1 is http://testurl1.com and in cell G1 is http://testurl2.com.
I would like to have a button or link or something in cell D1 that when I click it will open both of these links. I can do this manually with Alt-Enter but haven't been able to translate that to code.
I have been able to open both these urls from a menu item, but when I try calling the code from a cell it says
Exception: Cannot call SpreadsheetApp.getUi() from this context.
But the code works from a menu item. Weird. The code I'm currently trying to use is below but I am open to any suggestions!
function callOthers() {
myFunction()
Utilities.sleep(1500);
myFunction2()
}
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var selection = sheet.getRange("F1").getValue();
var html = "<script>window.open('" + selection + "');google.script.host.close();</script>";
var userInterface = HtmlService.createHtmlOutput(html);
SpreadsheetApp.getUi().showModalDialog(userInterface, 'Open Tab');
}
function myFunction2() {
var sheet = SpreadsheetApp.getActiveSheet();
var selection2 = sheet.getRange("G1").getValue();
var html2 = "<script>window.open('" + selection2 + "');google.script.host.close();</script>";
var userInterface2 = HtmlService.createHtmlOutput(html2);
SpreadsheetApp.getUi().showModalDialog(userInterface2, 'Open Tab');
}
Problem
Custom function is blocked from being run when used in a cell
Explanation
There are three main ways of making a bound script function available in the Spreadsheet UI:
As a custom function that can be used like a formula
As a menu item that will run the function on click
As a "button" created via image or drawing that will run the function on click
All three have different execution context and limitations on what they can and cannot access, the most restrictive being the first. Custom functions execution context is bound to the cell it is called in, so you cannot do anything that affects the UI as a whole, which getUi() allows to do.
Additionally, since showModalDialog is a method that requires authorization on behalf of the user, even if the getUi() method was available, you could not show the dialog due to the fact that custom functions never ask users to authorize access to personal data.
Solution
If you want to interact with UI, you should either create a menu or a button as mentioned before.
Please note that users will have to give your script their permission for the following scope:
https://www.googleapis.com/auth/script.container.ui
References
Custom functions guide
showModalDialog method reference
getUi() method reference

Run Google Sheets script when formula updates cell

After much searching, I have solved the first part of my problem: I found the below script which copies data from one range and adds it to another sheet.
However, the range that it is copying from is going to be automatically updating via a formula. So, my next challenge is - how do I get the script to run when the cell changes?
I believe there is a way to 'watch cells' for changes, but I'm really not very technical so I haven't been able to figure it out!
Potentially added complication - I believe 'on edit' scripts only run when the spreadsheet is open, is that right? If so, I'm also going to need to figure out how to get the script to run to check for new values on timed intervals.
Here's my current script:
function moveValuesOnly() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange("Sheet1!F1:H3");
var destSheet = ss.getSheetByName("Feuil2"); // Déterminer l'emplacement de la première ligne vide. var destRange = destSheet.getRange(destSheet.getLastRow()+1,1); source.copyTo (destRange, {contentsOnly: true}); source.clear ();
}
How to run a script on time-driven trigger:
You can use the script you already have
You can bind to it a time-driven trigger by
Going on Edit -> Current Project's triggers
Selecting create new trigger
Specifying the function to which you want to bind the trigger
Specifying that the trigger shall be time-driven
Select type of time based trigger and interval as desired
Click on Save

pre-loading custom functions when running sheets daily script

I'm using the 'Cryptofinance' custom function in Google spreadsheets. I have written a custom script which runs daily using the trigger functionality of the app scripts.
function daily() {
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Liquidity");
var value = sh.getRange("B36").getValue();
var lastRow = whichRow();
lastRow += 1;
ss.getSheetByName("Liquidity over time").getRange("B" + lastRow).setValue(value);
ss.getSheetByName("Liquidity over time").getRange("A" + lastRow).setValue(new Date());
}
function whichRow() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var Avals = ss.getSheetByName("Liquidity over time").getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
return Alast;
}
Basically it should pick up the value from a field and add a row so I can run a chart on this column.
The output when I run it manually from the script editor can look like this;
1337999,52
The output when it gets run by the daily function looks like this:
#NAME?
It didn't help with the .flush() function and I haven't been able to understand the sheets lifecycle in combination with the custom function.
How can I make sure the sheet is pre-loaded before the script runs?
You need to open the Spreadsheet and then set it as active:
var ss = SpreadsheetApp.openById("1234567890");
SpreadsheetApp.setActiveSpreadsheet(ss);
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#setActiveSpreadsheet(Spreadsheet)
Short answer
On time-driven triggers avoid the use of call functions, even custom functions, that use getActiveSpreadsheet and other "get active" methods. Instead use openById or other similar methods.
Explanation
SpreadsheetApp.flush() ensures the pending changes made to the script are applied, so it doesn't make sense to put it as the first action of a function.
On the other hand, on Google Apps Script, the user that has opened the spreadsheet establish which spreadsheet is active, on time-driven triggers getActiveSpreadsheet returns null, in other words, we could say that "active" means "being used at this time by an user".

Is there a way to run google docs script under the script owner's authorization?

I have a google sheet that is a master database of orders entered by a number of dealers. Therefore, this master sheet must have limited edit access. I want created a number of other sheets (one for each dealer) through which they can enter orders and added to my master sheet via a script running in those sheets. Is this possible? When I tried this, it denied them access to the master sheet. Is there a way around this?
One work around that I've used for this problem is to set an installable trigger to run on a regular time interval.
Installable triggers run on the owner of the trigger's authority, so it will be able to access both the main spreadsheet as well as each dealer's. The trick is to assign a timed trigger to a function that checks each dealer's sheet for updates and then makes the appropraite change to the main spreadsheet. You'll want to be sure that the trigger doesn't take too long to run or run too frequently since you have a limited amount of script run time each day.
Something like the following:
function myTrigger() {
var time = new Date();
// maybe check to see if it's night or other times that dealers won't update
// that way you can return early and don't waste quota hours
var dealerSpreadsheetIds = ["id1", "id2", ...];
var dealerSheetName = "Deals";
for (var i = 0; i < dealerSpreadsheetIds.length; i++) {
var sheet = SpreadsheetApp.openById(dealerSpreadsheetIds[i]).getSheetByName(dealerSheetName);
// check Deals sheet ranges for updates
// if there is an update, update the main spreadsheet
}
}

Categories

Resources