Max number of script in a spreadsheet [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
In my spreadsheet, I have inserted 35 project in GAS to generate google doc from the same sheet with the placeholder present in the docs.
The script takes the fields from each row in the sheet the script is contained in and using a Google Doc template (identified by TEMPLATE_ID) creates a PDF doc. The fields replace the place-holders in the template. The place-holders are identified by having a % either side, e.g. %Name%. It is invoked by the “Create PDFs” menu.
Naturally I have created a project for each Google Doc template (because I need 35 different doc from 35 different templates) and so in my sheet i have about 35 custom voice in menu that activate each script. Sometimes some scripts not appears all together and so I must to reload the sheet to find the script I need.
Why? There is a way to avoid this?
The script is this:
var TEMPLATE_ID = 'xxxxxxxx';
var PDF_FILE_NAME = '';
var RESULTS_FOLDER_ID = 'xxxxxxx';
var SENT_COLUMN_NAME = 'Date Sent';
var FILE_NAME_COLUMN_NAME = 'File Name';
var EMAIL_COLUMN_NAME = 'Email';
var DATE_FORMAT = 'yyyy/MM/dd';
var DATE_TIME_FORMAT = 'yyyy/MM/dd HH:mm:ss';
function sendMultiplePdfs() {
var ui = SpreadsheetApp.getUi();
if (TEMPLATE_ID === '') {
throw new Error('TEMPLATE_ID needs to be defined in Code.gs');
return;
}
var templateFile = DriveApp.getFileById(TEMPLATE_ID);
var activeSheet = SpreadsheetApp.getActiveSheet();
var ranges = activeSheet.getActiveRangeList().getRanges();
var activeRows = [];
ranges.forEach(function(range) {
activeRows.push(range.getValues());
})
Update:
Solved by replacing the Template ID taking the value dynamically from a cell:
var ss = SpreadsheetApp.openById("ID_OF_THE_SS").getSheetByName("SHEET_NAME");
var TEMPLATE_ID = ss.getRange("RANGE_OF_THE_ID").getValue();

AFAIK there isn't a max number of projects that can be bounded to a G Suite editor document but having simple triggers on them could cause problems due to a "race - condition"
Rhetoric question
If there are multiple onOpen each of them creating a custom menu, will all of them be displayed correctly always on the same order?
One approach is to "parameterize" your project, i.e. create 35 functions to call a parameterized function receiving the template id and other parameters
Those 35 functions could be called from a menu, from images, among other ways to call them.
In Google Apps Script / JavaScript a function looks like this:
function doSomething(){
console.info('Hello world!');
}
the parameterized version could be
function saySomething(message){
console.info(message);
}
Then you call saySomething by passing a value for the parameter
function greetTheWorld(){
var message = 'Hello world!';
saySomethin(message);
}
In the case of this project you might put all the global variables in an array of object, having one object for each template.
var settings = [
{ /* First template */
TEMPLATE_ID:'xxxxxxxx',
PDF_FILE_NAME:'',
RESULTS_FOLDER_ID:'xxxxxxx',
SENT_COLUMN_NAME:'Date Sent',
FILE_NAME_COLUMN_NAME:'File Name',
EMAIL_COLUMN_NAME:'Email',
DATE_FORMAT:'yyyy/MM/dd',
DATE_TIME_FORMAT:'yyyy/MM/dd HH:mm:ss'
},
{ /* Second template */
TEMPLATE_ID:'xxxxxxxx',
PDF_FILE_NAME:'',
RESULTS_FOLDER_ID:'xxxxxxx',
SENT_COLUMN_NAME:'Date Sent',
FILE_NAME_COLUMN_NAME:'File Name',
EMAIL_COLUMN_NAME:'Email',
DATE_FORMAT:'yyyy/MM/dd',
DATE_TIME_FORMAT:'yyyy/MM/dd HH:mm:ss'
}
]
The pass the corresponding object of the parameterized function which previously was prepared to receive the corresponding values as an object.
Reference
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions

Related

How can a drop down dynaically change a web app?

I am working with a Google App Script web app that is going to be used to display student micro-credentials. The goal is to make it so I can use a dropdown to choose which classes are displayed. I have created the dropdown on the web app by copying from W3Schools, but it doesn't actually function. I need some help getting the dropdown to do what I need it today.
In the example screen you can see the view I have set up and the dropdown with three classes:
The data for this web app is stored on a Google Sheet, like this:
And the doGet looks like this:
function doGet(e) {
var htmlOutput = HtmlService.createTemplateFromFile('WebApp');
var pictures = getPictures(classSelection);
var names = getNames(classSelection);
var cutBelts = getCutBelts(classSelection);
var measureBelts = getMeasureBelts(classSelection);
var bindBelts = getBindBelts(classSelection);
var classSize = 10;
if(pictures.length<10){
classSize=pictures.length;
}
htmlOutput.pictures = pictures;
htmlOutput.names = names;
htmlOutput.cutBelts = cutBelts;
htmlOutput.measureBelts = measureBelts;
htmlOutput.bindBelts = bindBelts;
htmlOutput.classSize = classSize;
return htmlOutput.evaluate();
}
Where the variable "classSelection" is equal to the name of the class (101, 201, or 202) and the five 'get' functions (getPictures, getNames) return the picture, names, etc for that class as an array.
Okay, so here is my specific issue I need help with.
How do I get the dropdown to send data (the class) back to the doGet so that the variable "classSelection" updates and displays only the selected class?
Again, for the code I used to create the dropdown (html, css, and script) see this link, I literally copy-pasted and only changed the drop down titles 😊

How Stop Formula from Using Updated Data? (Google Sheets)

I have a vlookup formula looking for names and returning the average for that person. I record these averages throughout the week, and identify them as W1, W2, W3, etc. in different columns. The problem is, the data I import only has ONE average on it, meaning that if I import it, it will override what I had already put in a few days ago using the same report, just an older version.
My question is, is there a way for me to stop the formula for W1 from updating when the data it is calling on changes? Essentially, to freeze the values? That way I don't have to keep adding new tabs to import the new data in an effort to save the history. The data is robust, and I am gathering more info than just averages, so I need the whole thing.
I wouldn't mind scripting something too that would help solve my issue, I just need some guidance.
Edit: thoughts on scripting a menu button that would copy, paste values only of a selected range that I could trigger right before I update the data?
I want to be able to select a range in my sheet, select the menu "Save Info", have it copy what I selected, and paste it right back where it already was. This will remove the formulas that would otherwise cause my values to change upon the new data import, and leave my history intact.
The following is what I have come up with so far, but I receive this error:
"TypeError: sourceSheet.getDataRange is not a function".
function saveInfo(){
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = spreadSheet.getActiveSheet
var sourceRange = sourceSheet.getDataRange();
var targetSheet = spreadSheet.getActiveSheet();
sourceRange.copyTo(targetSheet.getActiveRange());
}
function updateMenu() {
SpreadsheetApp.getActiveSpreadsheet().updateMenu('Save Info', generateMenu())
};
function onOpen() {
SpreadsheetApp.getActiveSpreadsheet().addMenu('Save Info', generateMenu());
};
function generateMenu() {
var entries = [{
name: "Save Data Before Update",
functionName: "saveInfo"
}];
return entries;
}
Any ideas??
Thanks!
Here you go:
function saveInfo() {
var range = SpreadsheetApp.getActiveSheet().getActiveRange();
var values = range.getDisplayValues();
range.setValues(values);
}
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Save Info')
.addItem('Save Data Before Update', 'saveInfo')
.addToUi();
}
The script converts data inside selected cells into a plain text.
But actually you don't need any script. You can just select the cells, press Ctrl+C and Ctrl+Shift+V.

How to pull a specific row from one spreadsheet to another, update it and then replace it on the original sheet

So I have two separate sheets, one with a data list full of unique names, their location and their current status. The second would have an input to type someones name and it would pull up the row that contains their current location/status(first function), from there I could change the status and run the second function that updates the first sheet with the new status. I have been googling all day trying to cobble together something that would work and I think I am almost there on the first function but I am stuck and any help to point me in the right direction would be greatly appreciated.
Ideally the first function would trigger upon typing the name in and the second would trigger upon changing the status but I can find a manual workaround if need be.
function dataPull() {
var data = SpreadsheetApp.openById('Spreadsheet_ID'); //replace with Data spreadsheet ID
var filteredRows = data.filter(function (data) {
var employee = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange('b2').getValue();
if (data[1] === employee) {
return data
}
});
SpreadsheetApp.getActiveSheet().getRange('A2:D').setValue(filter)
}
Here are some screenshots that will hopefully better explain what I am looking to accomplish.
Sample data
Type someones name in Input sheet
Pull up current status w/ function one
Update Status and run function two
Sample data updates to reflect change in status
Edit Dialog in a Sheet
There is two sections to this function. The top section triggers off of edits to the Edit sheet in column 2 and row 2 which is a dropdown that contains all of the name in the Data Sheet. An edit here cause the top section to run which reads the the data on the Data sheet and file a matching name when it finds it that line is loaded into columns 1 through 4 and row 2 of the Edit sheet. Then you can edit the status and click the checkbox to save it back to the Data sheet. The lower portion then runs which reset's the checkbox, clears the Edit range and loads the edits back into the Data Sheet.
Please take a look at the animation to see the process in action.
Just to let you know upfront, you can run this function from the script editor you must put it into you sheet and name your sheets properly. You must also set up the data validations for the two drop downs. If you try to run this function from the script editor you will get the Error: Cannot find method getsheet() of undefined
function onEdit(e) {
e.source.toast('Entry');
var sh=e.range.getSheet();
if(sh.getName()=='Edit' & e.range.columnStart==2 && e.range.rowStart==2) {
e.source.toast('flag1');
var found=false;
var dsh=e.source.getSheetByName('Data');
var vA=dsh.getRange(2,1,dsh.getLastRow()-1,dsh.getLastColumn()).getValues();
for(var i=0;i<vA.length;i++) {
if(vA[i][1]==e.range.getValue()) {
sh.getRange(2,1,1,4).setValues([vA[i]]);
found=true;
e.source.toast('Value Found at i = ' + i + 'value = ' + vA[i][1],'',-1);
break;
}
}
if(!found) {
e.source.toast('No Value found = ' + e.value);
}
Logger.log(vA);
}
if(sh.getName()=='Edit' & e.range.columnStart==5 && e.range.rowStart==2) {
e.range.setValue("FALSE");
dsh=e.source.getSheetByName('Data');
dsh.getRange(Number(e.range.offset(0,-4).getValue()+1),4).setValue(e.range.offset(0,-1).getValue());
sh.getRange(2,1,1,4).clearContent();
}
}
Data Sheet:
Edit Sheet:
Animation:
You can't use the built-in onEdit(e) trigger; as it behaves in the same manner as a custom function would eg.(Restricted to the sheet it's bound to).
You can install a trigger in your bound script, and have it execute your un-restricted function.
function importData(e){
// Get the cell where the user picked its name
var range = e.range;
// The Id of your data source sheet
var dataSheetId = 'XXXXXXXXXXXXX';
// Get all values from source sheet as an array
var data_values = SpreadsheetApp.openById(dataSheetId).getDataRange().getDisplayValues();
// Return the row with data for matching employee
var filteredRow = data_values.filter(check)[0];
// Input location data in input sheet
SpreadsheetApp.getActiveSheet().getRange(range.getRow(),range.getColumn()+1).setValue(filteredRow[2]);
}
function check(row) {
// Get the name that the user picked
var employee_name = SpreadsheetApp.getActiveSheet().getActiveCell().getValue();
// Check if it matches and return the row
if (row[1].toLowerCase() === employee_name.toLowerCase()) {
return row
}
}
You can install the trigger from within your Apps Script by following Edit/Current project's triggers/Add trigger.
As the event source for the trigger select: "From spreadsheet"; and for function to run select "importData" (or the name of your function).

InstallableTriger doesn't fire when using setValue() [duplicate]

This question already has an answer here:
Trigger onEdit() with a programmatic edit
(1 answer)
Closed 3 years ago.
I'm currently working on a GAS project, and facing a strange issue.
I've set up an installable trigger that detect any change in the column A, and launch a custom function (installableOnEdit). In case the row in which the modification has been done contains datas, I call a custom function (GetProductInfo) to make an API call that will write value in different cell.
If not I just clear some other rows.
My issue is, if I manually insert datas in the A column, then it works like a charm, but in case i'm using a function to write in the A column with the .setValue (from an other custom function), the trigger does not fire.
Here is my code :
function installableOnEdit(e) {
var ss = SpreadsheetApp.getActive();
var editedRange = e.source.getActiveRange();
var editedRow = editedRange.getRow();
var editedCol = editedRange.getColumn();
var url = editedRange.getValue();
var urlColumn = 1;
if (editedCol == urlColumn){
if (url != ""){
GetProductInfo(url, "material", editedRow, editedCol);
}else {
//Reset material
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data").getRange(editedRow, editedCol+3).setValue("");
}
}
}
Any ideas ?
Thanks to tehhowch i've been able to find a solution.
That's not gonna fit for everyone, but instead to use the trigger, i simply call my custom function that retrieve the information from the API (GetProductInfo), by calling it at the end of the function that make the .setValue().

Would like to pass a CSS ID to selector in a different page [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I would like to pass a variable in JQuery from one web page to another on the click of a link.
For example. I have two web pages (Page1.html and Page2.html) and both contain Jquery scripts
When a user clicks on a link within Page1.html , I would like a variable to be passed to the JQuery script that resides in Page2.html
Thanks so much!
With HTML5, you can use
var myValue = 10;
localStorage.setItem("the value", value);
To set a value in the local storage of your domain and use
localStorage.getItem("the value");
On your second page to retrieve the value.
Solution 1:
You can send the variable without jQuery in Page 1, just by passing the value in the URL.
Example:
Link
Solution 2:
The HTML in Page 1
Link
jQuery
jQuery(document).ready(function() {
jQuery('#element').click(function(e)
{
e.preventDefault();
var url=jQuery(this).attr('href');
var send_data="sample"; /* data you need to send */
document.location='page2.html?variable'+send_data
})
});
In Page2.html common for both the solutions
<script type="text/javascript">
var value = get_variable("variable"); /* The data you send from page1.html will be stored in this variable value */
function get_variable(variable)
{
var returnvalue = "";
var url = window.location;
var breaks = url.split('?'); /* Separating the file name and sent variables */
var values = breaks[1].split('&'); /* breaking for multiple arguements */
for ( var i=0; i<values.length; i++)
{
var valsplit = values[i].split('=');
if ( valsplit[0] == variable )
{
returnvalue = valsplit[1]; /* Returning our desired variable */
}
}
return returnvalue;
}
</script>

Categories