Run a function with onEdit on Google Sheets mobile app - google-apps-script

I made my function that it's working good for me now, but i have the issue to make it work on mobile so i tried another way to use the function OnEdit, so when it will be the value that i want to lunch the function that i created before, but for now it's not working and i don't know why it's not, i'm asking for you help with this small issue ;)
thank you
function onEdit(e) {
var range = e.range;
var spreadSheet = e.source;
var sheetName = spreadSheet.getActiveSheet().getName();
var column = range.getColumn();
var row = range.getRow();
var value = SpreadsheetApp.getActiveSheet().getRange(row, column).getValue();
if(sheetName == 'New Orders' && column == 12 && value=='COMMANDE VALIDER')
{
VALIDERCOMMANDE();
}
}
function VALIDERCOMMANDE() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("New Orders");
var url = "https://docs.google.com/spreadsheets/d/1eTWG_XZt-3CMzkxgKM4pCvD41deGMdka37eQkHM9oDg/edit#gid=0";
var ss2 = SpreadsheetApp.openByUrl(url);
var pasteSheet = ss2.getSheetByName("Order Pull");
// get source range
var max = copySheet.getMaxRows().toString();
var range = copySheet.getRange(2, 1, max, 12);
var dataValues = range.getValues();
for (i = 1; i < dataValues.length; i++) {
if (dataValues[i][11] === 'COMMANDE VALIDER') {
pasteSheet.appendRow([dataValues[i][0],
dataValues[i][1],
dataValues[i][2],
dataValues[i][3],
dataValues[i][4],
dataValues[i][5],
dataValues[i][6],
dataValues[i][7],
dataValues[i][8],
dataValues[i][9],
dataValues[i][10],
dataValues[i][11]]);
var clearRow = i + 2;
copySheet.getRange('D' + clearRow + ':L' + clearRow).clearContent();
}
}
// get destination range
var destination = pasteSheet.getRange(pasteSheet.getLastRow() + 1, 1, max, 1);
// clear source values
Browser.msgBox('Commande Confirmer');
}

Try this way
function onMyEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() == 'New Orders' && e.range.columnStart == 12 && e.value == 'COMMANDE VALIDER') {
VALIDERCOMMANDE();
}
}
function VALIDERCOMMANDE() {
var ss = SpreadsheetApp.getActive();
var csh = ss.getSheetByName("New Orders");
var id = "1eTWG_XZt-3CMzkxgKM4pCvD41deGMdka37eQkHM9oDg";
var ss2 = SpreadsheetApp.openById(id);
var psh = ss2.getSheetByName("Order Pull");
var vs = csh.getRange(2,1,csh.getLastRow() - 1, 12).getValues().filter(r => r[11] == 'COMMANDE VALIDER').filter(e => e);
psh.getRange(psh.getLastRow() + 1, 1, vs.length, 12).setValues(vs);
}
I often find that onEdits are not reliable on mobile and sometimes the trigger process has to be repeated

Class Browser, Class UI and SpreadsheetApp.toast don't work in the Google Sheets mobile apps (iOS and Android). By the other hand, instead of using a simple trigger you should use an installable trigger because SpreasheetApp.openByUrl method requires authorization to run.
Change the name of the onEdit function, remove Browser.msgBox('Commande Confirmer'); and create an installable on edit function calling the renamed function should make your script work on the mobile apps
If you really need to have a custom notification when the onEdit function finish, you might send write a message or image on certain range. If you use on edit installable trigger you might also send an email or call an external API.
Related
Executing Google Apps Script Functions from Mobile App
Google Apps Script toast messages don't appear for anonymous editors
why is my trigger status "Paused" when triggered from mobile

Related

Move row to new tab after sheet updates automatically

I need to move rows from a tab based on a cell including "lep". The problem is that it doesn't read the info already on the sheet when it's opened (since it is a sheet that automatically updates new sales from Shopify via Zapier).
What would be the solution for this? I tried onEdit & onOpen already and neither work.
function onOpen(e) {
// assumes source data in sheet named SHOPIFY
// target sheet of move to named ORG
// test column with yes is col 17 or Q
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = e.source.getActiveSheet();
var r = e.source.getActiveRange();
if(s.getName() == "SHOPIFY" && r.getColumn() == 17 && r.getValue().includes("lep")) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("ORG");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
function moveRows() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('SHOPIFY');
const tsh = ss.getSheetByName('ORG')
const vs = sh.getDataRange().getValues();//you may wish to change the range to not include headers
let d=0;
vs.forEach((r,i)=>{
if(r[16].toString().includes("lep")) {
tsh.appendRow(r);
sh.deleteRow(i+1-d++);
}
});
}
function onMyOpen() {
//needs installable trigger
moveRows();
}
An onEdit() simple trigger will only run when the user hand edits the spreadsheet.
An onOpen() simple trigger will only run when you open the spreadsheet in a web browser, and its event object does not include information about any recent changes in the spreadsheet.
To detect changes made by Zapier you will need an on change installable trigger. See the moveRowsFromSpreadsheetToSpreadsheet_ script for an example of how to do that.

Showing exception error while trying to send emails with a sheet as an excel attachment

I am trying to send emails with a specific tab of a Google Spreadsheet as an Excel attachment to 40-50 students using installable edit trigger. It is showing
Exception: You do not have permission to call UrlFetchApp.fetch. Required permissions: googleapis.com/auth/script.external_request.
I reviewed several related posts and answer at Stackoverflow and Google but can't find anyway to do it manually.
My codes are:
function classAttendance(e){
var spreadsheet = SpreadsheetApp.getActive();
var dashboard = spreadsheet.getSheetByName("Dashboard");
var sheetName = dashboard.getRange("A4").getValue();
var sheetw = dashboard.getRange("A8");
var sheetw2 = dashboard.getRange("G8");
if (sheetName == 'All'){
if (e.range.getA1Notation() === 'C6' && e.range.getValue() === "Send Emails") {
sheetw.setValue('Sending emails to all students. Please Wait!').setFontColor('Red');
//refreshSheet();
sendEmails();
sheetw.setValue('You may take class attendance now. Thank You!').setFontColor('Green');
sheetw2.setValue('You may do manual entry now. Thank You!').setFontColor('Green');
}
if ((e.range.getA1Notation() === 'C6') && (e.range.getValue() === "Start 1-Period" || e.range.getValue() === "Start 2-Period" || e.range.getValue() === "Error Correction")) {
dashboard.getRange("C6").setValue('Please Select');
}
}
}
function sendEmails(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssID = ss.getId();
var sheetName = ss.getName();
var sh = SpreadsheetApp.getActive();
var sheet1 = sh.getSheetByName("TempDataSet");
var shID = sheet1.getSheetId().toString();
var subject = 'Your Attendance Record at BDU';
var body = 'Dear Student,'+ '\n\n' + 'Greetings! Please find the attendance record attached for your reference.' + '\n\n' + 'Thank you.';
var requestData = {"method": "GET", "headers":{"Authorization":"Bearer "+ScriptApp.getOAuthToken()}};
var url = "https://docs.google.com/spreadsheets/d/"+ ssID + "/export?format=xlsx&id="+ssID+"&gid="+shID;
var result = UrlFetchApp.fetch(url , requestData);
var contents = result.getContent();
var column = 3;
contents.sort({column: column, ascending:true});
var sheet2 = sh.getSheetByName('StudentList');
var data = sheet2.getLastRow();
var students = [];
var students = sheet2.getRange(2, 6, data).getValues();
for (var i=0; i<students.length; i++){ // you are looping through rows and selecting the 1st and only column index
if (students[i][0] !== ''){
MailApp.sendEmail(students[i][0].toString(), subject ,body, {attachments:[{fileName:sheetName+".xls", content:contents, mimeType:"application//xls"}]});
}
}
}
I created a standalone scripts where there are many functions including sendEmails() at my Google drive, then invoked the scripts as a library to my Google spreadsheet. Then I called the library in the script editor of my Google Sheet and also created an onEdit trigger for sendEmails(). All other functions in the library called are working fine.
The library seems to be added after adding the trigger. Hence authorization scopes are missing from previous authorization. The following should trigger re-authorization:
Remove the installed edit trigger and re-add it.
Click Run button after selecting classAttendance2 manually from script editor>

function onEdit() runs only partially

I have a very frustrating problem on my hands and I turn to you for help once more. I had the onEdit() function below which, together with the auxiliary functions, worked fine.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var activeCell = activeSheet.getActiveCell();
//Check if the sheet is a JOb sheet and the cell us the status cell
if ( activeSheet.getName().indexOf("Job ID") != -1 && activeCell.getRow() == 4 && activeCell.getColumn() == 15 ) {
var targetSheet = ss.getSheetByName('Active Jobs');
var jobRowNumber = findJobIdRow();
var sourceCell = activeSheet.getRange(4,15);
sourceCell.copyTo(targetSheet.getRange(jobRowNumber,16));
}
if (activeSheet.getName().indexOf("Job ID") != -1 && activeCell.getRow() == 2 && activeCell.getColumn() == 15){
var switchValue = activeCell.getValue();
switch (switchValue){
case "On hold (i)":
case "On hold (ii)":
case "On hold (iii)":
case "To be assigned":
//Write date to active jobs sheet
addDateToActive("TBC");
break;
case "In progress":
var newDate = Browser.inputBox("Please enter report out date, example 18-Aug-2017");
addDateToActive(newDate);
break;
//default:
//Browser.msgBox("GOTHERE");
}
}
}
function findJobIdRow() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var jobID = ss.getActiveSheet().getRange(2,1).getValue();
var column = ss.getSheetByName('Active Jobs').getRange(2,1,ss.getSheetByName('Active Jobs').getMaxRows()-2,1);
var values = column.getValues(); // get all data in one call
for(var ct = 0; ct < values.length-1; ct++){
if(values[ct][0] == jobID){
var ct = ct+2;
break;
}
}
return ct;
}
function addDateToActive(input){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var activeCell = activeSheet.getActiveCell();
var jobid = activeSheet.getRange(2,1).getValue().toString();
var activeJobSheet = ss.getSheetByName("Active Jobs");
var activeJobs = activeJobSheet.getRange(1,1,activeJobSheet.getLastRow(),1).getValues();
activeJobs = ColumnToArray(activeJobs);
var jobrow = activeJobs.indexOf(jobid)+1;
if (jobrow == -1){
Browser.msgBox("Job Id not preent on Active Jobs sheet");
}else{
activeJobSheet.getRange(jobrow,15).setValue(input);
}
}
Then I included some code in this script which was supposed to send out some e-mails to people if some dates were approaching today's date. There were some problems with that code because of authorization requirement so I moved it into it's own separate function and came back to the original script that is posted above. Now the problem I am facing is, although this script works fine if ran from the script editor, manually run from a drawing button in the spreadsheet, or is ran by a on edit trigger I set up from the "Current project triggers" menu, it will not do the entire script if the script is triggered by the onEdit() function name. It does the first bit where it copies the content of a cell across but not the second bit with the case switch.
The obvious fix would be to just set up the trigger from the "Current project triggers" but this onEdit detection needs to apply to anyone in my team that edits this sheet. If I set it up like that it will work for me but no one else from my team.
Any help would be appreciated.
Setting up the trigger via the function name onEdit() proving tricky I wrote this bit of code and attached it to a drawing in the sheet. Then instructed all the users to click it which set up the trigger for them. This solved the problem and the trigger works fine now.
function triggerSetUp(){
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("enforcer").forSpreadsheet(sheet).onEdit().create();
}

Google Spreadsheet unable to deploy web app script --

I've been trying to deploy this web app bound to my shared spreadsheet. Basically it's a script that locks a cell after it's been edited. It is working just fine when I access it, however when I switch to another user and try, it doesn't function. You would think it would be a sharing permission setting, but I've changed everything to public and still no luck. Can you someone please help?
Here is the script:
function doGet(e) {
var sheet = SpreadsheetApp.openById('1234567891011');
}
function onEdit(){
var masterSheetName = "PlaceYourSquare" // sheet where the cells are protected from updates
var helperSheetName = "Helper" // sheet where the values are copied for later checking
var firstDataRow = 1; // only take into account edits on or below this row
var firstDataColumn = 1; // only take into account edits on or to the right of this column
var ss = SpreadsheetApp.getActiveSpreadsheet();
var masterSheet = ss.getActiveSheet();
if (masterSheet.getName() != masterSheetName) return;
var masterCell = masterSheet.getActiveCell();
if (masterCell.getRow() < firstDataRow || masterCell.getColumn() < firstDataColumn) return;
var helperSheet = ss.getSheetByName(helperSheetName);
var helperCell = helperSheet.getRange(masterCell.getA1Notation());
var newValue = masterCell.getValue();
var oldValue = helperCell.getValue();
if (oldValue == "") {
helperCell.setValue(newValue);
} else {
masterCell.setValue(oldValue);
}
}

Google Apps Script - Make onEdit() recognize setValue() changes

I have a Spreadsheet with some functions. One of them is a onEdit(event) function that copies some values to other sheets based on conditions. This is the code (simplified but with the important parts intact):
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.range;
if(s.getName() === "Lista" && r.getColumn() === 9 && r.getValue() === "Posicionada") {
var sheetname = s.getRange(r.getRow(),3).getValue();
var columnRef = s.getRange(r.getRow(),4).getValue();
var row = s.getRange(r.getRow(),5).getValue();
var targetSheet = ss.getSheetByName("Mapa " + sheetname);
var headers = targetSheet.getRange(1, 1, 1, targetSheet.getLastColumn());
for (var i = 0; i < headers; i++) {
if (headers[i] === columnRef) {
break;
}
}
var column;
if (columnRef === "A1") {
column = 2;
}
else if (columnRef === "A2") {
column = 3;
}
else if (columnRef === "B1") {
column = 4;
}
else if (columnRef === "B2") {
column = 5;
}
if (sheetname === "N2") {
row = row - 30;
}
if (sheetname === "N3") {
column = column - 10;
row = row - 42;
}
targetSheet.getRange(row,column).setValue(s.getRange(r.getRow(), 1, 1, 1).getValue());
}
}
The code works as it should when I manually edit the cell. But, I have a code that edit the cell when the user press a button in a sidebar, this is the code:
function positionMU(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveCell().activate();
var cellLevel = cell.offset(0,2);
var cellLetter = cell.offset(0,3);
var cellNumber = cell.offset(0,4);
var cellStatus = cell.offset(0,8);
var dbq = "Posicionada";
var fora = "Pendente de recebimento";
if (cellStatus.getValue() == "Aguardando posicionamento"){
cellStatus.setValue(dbq); //attention in this line
}
else if (cellStatus.getValue() == "Aguardando saĆ­da"){
cellStatus.setValue(fora);
var cellExitDate = cell.offset(0,6);
cellExitDate.setValue(getDate());
}
}
As you can see, this function change the cell content with setValue(), but, when I use this function, the value of the cell changes, but the onEdit() trigger doesn't work.
How can I make the onEdit() trigger recognize changes made with setValue()?
You are right. onEdit() only triggers if the range is edited manually. As can be seen here, onEdit() triggers when a value is changed by the user.
I tested the function by making function to insert values into a column for which my onEdit responds and nothing happens. Including various other techniques that I could think of. Best thing to do here is to suggest this as an enhancement on App Script's Issue Tracker.
However, I made it work by writing another function to be called when another function in the script makes changes to the sheet. These are the test functions I wrote:
function addValues()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getDataRange();
var book = "Book";
var cancel = "Cancel";
var maxRow = range.getLastRow()+1;
for(var i=0; i<4; i++)
{
if (i%2 == 0)
{
sheet.getRange(maxRow, 1).setValue(book);
autoChanges(maxRow);
}else{
sheet.getRange(maxRow, 1).setValue(cancel);
autoChanges(maxRow);
}
maxRow++;
}
}
autoChanges function:
function autoChanges(row)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getDataRange();
var data = range.getValues();
var response = "";
sheet.getRange(row, 2).protect();
response = data[row-1][0];
if (response == "Book")
{
sheet.getRange(row, 2).canEdit();
}else{
sheet.getRange(row, 2).setValue("--NA--");
}
}
Not the most elegant solution but this seems to be the only workaround for what you are trying to do.
There are some very good reasons why calling range.setValue() doesn't trigger the onEdit event, and most of them have to do with infinite recursion. In fact, you call setValue() yourself WITHIN onEdit(). This would trigger a recursive call, and from what I can see, you have no provision for handling the base case and thus your code would explode if setValue() did what you want.
Why not simply take all of your code out of your event handler, and put it into another function:
function onEdit (e) {
return handleEdits(e.range);
}
function handleEdits(r) {
s = r.getSheet();
ss = s.getParent();
//the rest of your code should drop right in.
}
then, inside your autoChanges function, go ahead and call handleEdits, passing it an appropriate range, after your call to setValue().
If you like to play with fire, and I personally do, you can call the onEdit(e) function after you make a change. Just send in an object whatever is called and used by the e object.
For me, I just needed to add:
var e={};
e.range=the range you are making a change to in the script;
e.source = SpreadsheetApp.getActiveSpreadsheet();//or make sure you have the sheet for wherever you are setting the value
e.value=whatever value you are setting
e.oldValue=if you onEdit needs this, set it here
//if you are using any of the other standard or special properties called by your onEdit...just add them before calling the function.
onEdit(e);//call the function and give it what it needs.