I created a function that's tied to a custom menu item in a google spreadsheet and is meant to detect the current row and perform some checking. The issue is that every time i run the menu item > script it always detect row 1 and not the current script. here's the code for reference:
function updateCalendarItems(){
//this function detects the current row and updates the main and follow up calendar events
//Get the current row
var ss = SpreadsheetApp.openById('<deleted>');
var sheet = ss.getSheetByName('db_clientvisit');
Logger.log('Sheet Name: '+sheet.getName()); //this logs the correct sheet name
// var range = sheet.getActiveCell();
var rowNum = sheet.getActiveCell().getRow();
Logger.log(rowNum); //always logs 1
var range = sheet.getRange(rowNum, 1, 1, 13).getValues(); //always returns the first row
Logger.log(range);
var ui = SpreadsheetApp.getUi();
ui.alert('Row Num is :'+rowNum+' Column Num is: '+sheet.getActiveCell().getColumn());
return;
var range = sheet.getRange(rowNum, 1, 1, 13);
var row = range.getValues()[0];
Logger.log(row);
//open the calendar
var calendarID = 'loveyourself.ph_umvj5k6vo45ei0mbh423g97ebg#group.calendar.google.com';
var calendar = CalendarApp.getCalendarById(calendarID);
//update the calendar...
}
Use var ss = SpreadsheetApp.getActive().
When you use SpreadsheetApp.openById('<deleted>'), you're essentially opening up a new session of the spreadsheet instead of your active session. So Apps Script isn't able to get the "active" ranges.
Similarly, you may also want to try using SpreadsheetApp.getCurrentCell().
function updateCalendarItems() {
var currentCell = SpreadsheetApp.getCurrentCell();
var rowNum = currentCell.getRow();
var ui = SpreadsheetApp.getUi();
ui.alert('Row Num is :'+rowNum+' Column Num is: '+currentCell.getColumn());
return;
}
Related
I already try everthing but I cant make this work =/
I'm trying to copy data from one spreadsheet to other using setValues(), because link doesn't work for me. I also need to keep the trigger on edit.
So, I create one fuction called AddConvocacao, and always when have any change the script run.
function addConvocacao(e){
var linha = e.range.getRow(); //get the number of the line, where have edit
var nome = e.source.getActiveSheet().getRange(linha,2).getValue(); //get the value of the field
var targetSheet = SpreadsheetApp.openById('1iQbZ7iB9ddc-HwLK9vG0eVEeWWqXKJZ0ry7U_Hm4SkQ') //open the other spreedsheet
var targetName = targetSheet.getSheetByName('Pac'); //open the tab
var lastRow = targetName.getLastRow(); //count the last row in this tab
lastRow = lastRow+1; //add 1
targetName.getRange(lastRow, 2).setValue(nome); // set the value
// targetName.getRange(lastRow, 3).setValue(valorCol7);
// targetName.getRange(lastRow, 5).setValue(dose);
// targetName.getRange(lastRow, 6).setValue(diagnostico);
// targetName.getRange(lastRow, 7).setValue(medico);
}
why dosen't work when I use on edit?
Thanks so much! =)
I did it a little different I think. I put checkboxes in column one and capture the value from column 2 and sent it to the other spreadsheet to the bottom of column 2
function onMyEdit(e) {
//e.source.toast('entry');
const sh = e.range.getSheet();
//Logger.log(JSON.stringify(e));
if (sh.getName() == 'Sheet1' && e.range.columnStart==1 && e.value=="TRUE") {
//e.source.toast('cond');
const v = sh.getRange(e.range.rowStart, 2).getValue();
var tss = SpreadsheetApp.openById(getGlobal('targetid'));
var tsh = tss.getSheetByName('Sheet1');
tsh.getRange(tsh.getLastRow() + 1, 2).setValue(v);
e.range.setValue("FALSE");
}
}
You must use an installable trigger to us openById();
getGlobal(targetid) just gets a spreadsheet id you can replace that with the id
Also I limited the action to only one sheet and only when I set the checkbox to true. I reset it back to false in the code.
You'll need to modify a few things to get it to work for you because when I'm doing the examples I do it my way.
I have created a code which replaces placeholders on google slides. The starting point of this project is a google form. Once the google form has been submitted - then the relevant data from google form is entered on the google slides template. See below code. I am looking to create a question on the form where people will be able to select multiple slides to be included (2 Credential slides for example out of 10)
function PoD() {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("A-PoD").activate();
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = ss.getLastRow()
for (var i =2;i<lr;i++){
if(ss.getRange(i, 1).getValue()){
//Make a copy of the template file
var documentId = DriveApp.getFileById('1REHMrl6kfzXbgSipvBDkNitkfsM8tJsUSAICggxNsHw').makeCopy().getId();
var Name_of_programme = ss.getRange(i, 2).getValue();
DriveApp.getFileById(documentId).setName("PwC's Academy_"+Name_of_client+"_"+Name_of_programme+"_"+Month);
var FileName = Name_of_programme;
//Get the document body as a variable
var body = SlidesApp.openById(documentId);
body.replaceAllText('{Name of programme}', Name_of_programme);
var lastSlide = body.getSlides();
lastSlide[5].remove();
I am looking to continue the script to include a function to select multiple slides. I saw the below script to copy one slide but have not been able to figure out how to copy multiple slides easily.
var srcPresentationId = "### source fileId ###";
var copysrcSlideIndex = 0; // 0 means page 1.
var copydstSlideIndex = 0; // 0 means page 1.
var src = SlidesApp.openById(srcPresentationId).getSlides()[copysrcSlideIndex];
SlidesApp.getActivePresentation().insertSlide(copydstSlideIndex, src);
I want to give people the choice to select which slides to include on the google form as multiple choice.
At the back end of the script, would I need to map the names of the slides with slide numbers? or can have include a unique reference in a text box on each slide and then select the relevant slide? Thinking out loud here. Any guidance would be appreciated.
You want to copy the 5, 7, and 9 pages (indexes of 4, 6 and 8) in the master Google Slides to other Google Slides.
You want to achieve this using Google Apps Script.
I could understand like above. If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Flow:
Retrieve all slides from the master Google Slides.
Copy the required slide to the destination Google Slides in the loop.
Pattern 1:
Sample script:
Before you run the script, please set the variables.
function myFunction() {
var copyPageNumbers = [5, 7, 9]; // Please set the page number. This is not the index. So the 1st page is 1.
var masterGoogleSlidesId = "###"; // Please set the master Google Slides ID.
var destinationGoogleSlidesId = "###"; // Please set the destination Google Slides ID.
var offset = 1;
var src = SlidesApp.openById(masterGoogleSlidesId);
var dst = SlidesApp.openById(destinationGoogleSlidesId);
var slides = src.getSlides();
var page = 0;
slides.forEach(function(slide, i) {
if (copyPageNumbers.indexOf(i + 1) != -1) {
dst.insertSlide(offset + page, slide);
page++;
}
});
}
Pattern 2:
Sample script:
function myFunction() {
var copyPageNumbers = [5, 7, 9]; // Please set the page number. This is not the index. So the 1st page is 1.
var masterGoogleSlidesId = "###"; // Please set the master Google Slides ID.
var destinationGoogleSlidesId = "###"; // Please set the destination Google Slides ID.
var offset = 1;
var src = SlidesApp.openById(masterGoogleSlidesId);
var dst = SlidesApp.openById(destinationGoogleSlidesId);
var slides = src.getSlides();
copyPageNumbers.forEach(function(p, i) {
dst.insertSlide(offset + i, slides[p - 1]);
});
}
Note:
In both patterns, the pages of 5, 7 and 9 of the master Google Slides are copied from 2nd page in the destination Google Slides.
When var offset = 0 is used, the pages of 5, 7 and 9 of the master Google Slides are copied from 1st page in the destination Google Slides.
Reference:
insertSlide(insertionIndex, slide)
Thanks, #Tanaike, for the solutions!
With your code as a base, I was able to build a script to add slides to multiple slide decks in a single folder. I wanted to share for those who may need it. Code below...
function copySlides() {
// Array of slide numbers to grab [1, 2, 3,...]
var copyPageNumbers = [1]; // Please set the page number. This is not the index. So the 1st page is 1.
// Which deck contains the slides to copy
var masterGoogleSlidesId = '###'; // Please set the master Google Slides ID.
// Folder containing Slides to copy to
var folderID = '###';
var folderToCopyTo = DriveApp.getFolderById(folderID);
// Slide files in folder
var slidesInFolder = folderToCopyTo.getFilesByType(MimeType.GOOGLE_SLIDES);
var counter = 0;
var total = 0;
while (slidesInFolder.hasNext()) {
var file = slidesInFolder.next();
var destinationGoogleSlidesId = file.getId(); // Please set the destination Google Slides ID.
var offset = 0;
try {
var src = SlidesApp.openById(masterGoogleSlidesId);
var dst = SlidesApp.openById(destinationGoogleSlidesId);
var slides = src.getSlides();
copyPageNumbers.forEach(function (p, i) {
dst.insertSlide(offset + i, slides[p - 1]);
});
counter++;
}
catch (e) {
console.log(destinationGoogleSlidesId);
console.log(e);
}
total++;
}
console.log(counter + ' of ' + total + ' Slide Decks Updated');
}
I am currently using google forms to enable users to submit site changes. This is all working beautifully.
I have added an extra column that has ticket status. Now I have written a script that checks for when this is updated to Done and then moves that row into another sheet entitled done.
However this only works if i update a row that i manually added. If I change the column on a row created from the form entry it will not work. Has anyone seen this issue before. Code is below.
function onEdit(e){
/*
When a user updates a status to done the ticket gets moved to another sheet
*/
var sheetNameToWatch = "Form responses 1"; // The sheet to watch for changes
var columnNumberToWatch = 1; // The column where the change happens on the above sheet
var valueToWatch = "Done"; // What is the text you are looking for
var sheetNameToMoveTheRowTo = "Done"; // The Sheet name for where the row gets moved to.
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Get the active spreadsheet
var sheet = SpreadsheetApp.getActiveSheet(); // Get the active sheet
var range = sheet.getActiveCell(); // Get the current cell that has just been updated
// Check that you are on the correct sheet and column.
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo); // get a reference for the target sheet
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1); // get a reference for the target row
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange); // copy the row from current sheet to the new sheet
sheet.deleteRow(range.getRow()); // Delete the row from the old sheet
}
}
Yep, the onEdit function won't fire unless you do it manually, you'll want to use the onFormSubmit trigger, which will fire when a form response is received. This is a manually installed trigger connected to your form, which should be able to do the function above pretty much as written.
var form = FormApp.openById('1234567890abcdefghijklmnopqrstuvwxyz');
ScriptApp.newTrigger('myFunction')
.forForm(form)
.onFormSubmit()
.create();
To be safe, though, you may want to define your spreadsheet, sheet, and range by id or by name rather than by whether they are active, I believe getActiveWhatever() kinds of methods will return null if the spreadsheet isn't open.
As mentioned, using active is not the best idea.
Instead of:
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Get the active spreadsheet
var sheet = SpreadsheetApp.getActiveSheet(); // Get the active sheet
var range = sheet.getActiveCell(); // Get the current cell that has just been updated
Try:
var range = e.range;
var sheet = range.getSheet();
var ss = sheet.getParent();
If you try this you cannot execute it from the code editor because no event is passed. You must execute it by actually submitting a form.
Is there any way of adding a script to a Google spreadsheet to take info from certain fields on a sheet and add them to my Google calendar as an event.
E.g. The dates and times and an event title?
You can add a custom menu to your spreadsheet that will trigger the code to run when you choose a menu item.
Add an onOpen() simple trigger function to your code that will create the new menu when the spreadsheet opens:
Code.gs
function onOpen() { //Runs when spreadsheet is opened
SpreadsheetApp.getUi()
.createMenu('Custom Menu')
//Run a function named fncAddToCalender when menu item is choosen
.addItem('Display User Dialog', 'fncAddToCalender')
.addToUi();
};
Function that originally runs from menu trigger:
function fncAddToCalender() {
var arrayOfData = fncGetData(); //Runs the function that gets the data
fncAddCalenderEvent(arrayOfData); //Runs the function that adds the calender event
};
Function to get Data:
function fncGetData() {
//Get data from Spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; //Get the first sheet, index zero
var range = sheet.getRange(1, 1, 10, 3); //Get a REFERENCE to a range of cells
var values = range.getValues(); //Get the values out of the range
return values; //Sends data back to the function that called this function
};
Function to add Calender Event:
function fncAddCalenderEvent(argDataToAdd) {
//Code to add calender event
};
ive a function that does calculations on a table using jquery when any input field is updated. It works fine but i need to be able to call it update a specific row when i load in data. I cant seem to get it working properly either it updates when the an input field changes and it wont work when i call it to update a specific row.
Im trying to pass a parameter into the function to tell what row to update when i need it and when it detects a change event it checks if the variable was passed in. I was trying to check if the passed in variable was undefined or null but i cant seem to get to work. What ami doing wrong?
my code;
so a call to update a certain row;
////////////////////////////////////////////
//load prices and pid from range selected
////////////////////////////////////////////
$(document).ready(function(){
$("#range_select").change(function(event){
//get the range id
$id=$("#range_select").val();
var i;
var loadedValues;
var result;
var pid;
loadedValues=0;
//clear All the prices if loaded, reset background color
$(".price").val(0);
$(".price").css("background-color","#FFF");
//clear ALL product id
$(".productid").val(0);
///////////////////////////////////////////////////////////
//note the url will break if site changed
$.ajax({url:"/mysite/products/list_products_from_range/"+$id, success:function(result){
/*if(result.length==0){
//no results from ajax request
alert('No products found for this range.);
return false;
}*/
//parse the returned JSON object,for each parse of result we check the table
$.each(jQuery.parseJSON(result), function() {
//console.log("product id="+this['Product']['id']);
pid=this['Product']['id'];
var price=this['Product']['price'];
var height=this['Product']['height'];
var width=this['Product']['width'];
/*console.log("price="+price);
console.log("h="+height);
console.log("w="+width);*/
/////////////////////////////////////////////////////////////
//now we have to go through the table and insert the values
i=-1;
var rows = $("#productentry tr:gt(0)"); // skip the header row
rows.each(function(index) {
i++;
var h = $("td:eq(3) .h", this).val();
var w = $("td:eq(4) .w", this).val();
//console.log(h +'x'+w);
//console.log("if "+w+" = "+width+" and "+h+" = "+height);
//console.log('index='+index);
if(w==width && h==height){
//increment count of loaded values
loadedValues++;
//set the price
$("#listprice_"+i).val(price);
//set the pid
//alert(pid);
$("#productid_"+i).val(pid);
//change price textbox to visually show its chnaged
$("#listprice_"+i).css("background-color","#F60");
//update totals (notworking)
calculateTotal(i);
return false;
}
});
/////////////////////////////////////////////////////////////
});
alert('loaded '+loadedValues+' prices');
}});
});//end click event
});
/////////////////////////////////////////////////////
//any input field that changes updates the calculation, not working fully i.e load product prices
/////////////////////////////////////////////////////
$(document).ready(function(){
$(":input").change(calculateTotal);
});
////////////////////////////////////
//calculate total
///////////////////////////////////
var calculateTotal = function(index){
var $discountpercent = null;
var $total=null;
var $quantity=null;
var $id=null;
var $marginpercent=null;
var $margintotal=null;
var myArray=null;
console.log('index='+index + ' indexlen= '+index.length );
if(index === undefined){
console.log('getting id');
//get id of textbox
$id=$(this).attr('id');
//get the row id
$id=$id.toString();
myArray = $id.split('_');
$id=myArray[1];
}
else
{
console.log('setting id=index');
$id=index;
}
var $listprice= $("#listprice_"+$id).val();
//turn entered number into %
$discountpercent= $("#discountpercent_"+$id).val()/100;
$discountlistprice=$listprice-($listprice*$discountpercent);
//turn margin to % (note margin is global)
$marginpercent= $("#marginpercent_"+$id).val()/100;
//apply margin % to DLP
if($discountlistprice>0)
{
$margintotal=$discountlistprice+($discountlistprice*$marginpercent);
}
else
{
$margintotal=0;
}
//set rrp
$rrp=$margintotal;
$("#rrp_"+$id).val($rrp);
//quantity
$quantity=$("#quantity_"+$id).val();
//calculate total
$total=$quantity*$rrp;
//set the value
$("#discountlistprice_"+$id).val($discountlistprice);
//set the total by changing the total div
$("#total_"+$id).html($total);
}
Change your handler to an anonymous function:
$(document).ready(function(){
$(":input").change(function () {
var index = getIndex(); // however you are getting this value
calculateTotal(index);
});
});