Script to display board game matches based on criteria - google-apps-script

My apologies if my wording is confusing, as I am new to scripting and programming. I have a board game list with my friends that have the list of games we own, the estimated time it takes to play the game, and the min/max players required to play the game. A wonderful member of the community created a script where I can input the amount of players I have, and the amount of time we have on our hands, and the script would list the available games we could lay base off of my input. Currently, I input the players and times on line two of the script ( var gamesThatFitCriteria = findGames(4,50); ). I would like the script to take the values ofdesignated two cells on the sheet to create these numbers.
Here is the sheet (editable for all, I have a separate private copy) with details on what I would like to accomplish, as well as my current script.
https://docs.google.com/spreadsheets/d/1AFTr_ji5iz8BJU9_OkZ1Xhfb9hg9ARAaRXfdVx2Y8pU/edit?usp=sharing
function runThis() {
var gamesThatFitCriteria = findGames(4,50);
var userInterface=HtmlService.createHtmlOutput(gamesThatFitCriteria.join('<br />'));
SpreadsheetApp.getUi().showModelessDialog(userInterface, "Games")
}
function findGames(player, timeInMinutes) {
var games=SpreadsheetApp.getActive();
var sh=games.getActiveSheet();
var rg=sh.getRange(3,1,sh.getLastRow(),sh.getLastColumn());
var values=rg.getValues();
var result = [];
values.forEach(function(r){var name=r[0];var time=r[2];var minPlayer=r[3];var maxPlayer=r[4];if(time<=timeInMinutes && player >= minPlayer && player <= maxPlayer) {result.push(name);}});
return result;
}

You want to retrieve the values from the cells B2:B3 on the sheet of Look Here.
You want to use the retrieved values to valueOfB2 and valueOfB3 of var gamesThatFitCriteria = findGames(valueOfB2, valueOfB3);.
You want to achieve this by modifying your script.
If my understanding is correct, how about this modification?
Modified script:
When your script is modified, please modify the function of runThis() as follows.
function runThis() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Look Here");
var [[valueOfB2], [valueOfB3]] = sheet.getRange("B2:B3").getValues();
var gamesThatFitCriteria = findGames(valueOfB2, valueOfB3);
var userInterface=HtmlService.createHtmlOutput(gamesThatFitCriteria.join('<br />'));
SpreadsheetApp.getUi().showModelessDialog(userInterface, "Games")
}
Note:
In your shared Spreadsheet, there are 2 functions of findGames in the files of Get Games Dialogue and On Open. In this case, one of 2 functions of findGames is run. So please be careful this.
In your script, when you run the function of runThis on the sheet of Games, the retrieved values are displayed. When you run the function on the sheet of Look Here, no values are displayed. Please be careful this.
If you want to display the values on the sheet of Look Here, please modify var sh=games.getActiveSheet(); to var sh=games.getSheetByName("Games");.
Reference:
getSheetByName()
If I misunderstood your question and this was not the result you want, I apologize.

Related

Optimizing Script run time gathering large volume of spreadsheet tab information

I'm hoping that someone might have an alternative suggestion for a strategy for the Google Apps Script I wrote below to help it finish running before it times out. I have a lengthy list of Spreadsheets (about 200) that each have anywhere from 20-100 individual sheets/tabs in them. I'm trying to loop through the entire list of spreadsheets to gather information about each individual sheet (about 8,000 in total) but unfortunately it's running to slow to complete in one run.
Thanks in advance for any suggestions
function getListofTabs(urlName) {
var ssRecipeTable = SpreadsheetApp.openByUrl(urlName);
var tabs = ssRecipeTable.getSheets();
for(var i=0;i<tabs.length;i++){
sheetName = tabs[i].getName();
sheetID = tabs[i].getSheetId();
sheetURL = tabs[i].getParent().getId();
//Logger.log(sheetName,sheetID,sheetURL);
dataList.appendRow(['=HYPERLINK("https://docs.google.com/spreadsheets/d/'+tabs[i].getParent().getId()+'/edit#gid='+tabs[i].getSheetId()+'","'+tabs[i].getName()+'")',tabs[i].getName(),tabs[i].getParent().getId(),tabs[i].getSheetId()]);
}
}
//Function to feed getListofTabs function with list of all recipe workbooks
function getArray(){
//Temp location for active tests
var recipeDataSS = SpreadsheetApp.getActiveSpreadsheet();
//List of all Recipe workbooks from master Tested Recipe folder
var listofWorkbooks = recipeDataSS.getSheetByName('ListofWorkbooks');
//Location for data input sheet for Plx Upload
var dataList = recipeDataSS.getSheetByName('Spreadsheets2');
//gets list of workbooks urls, loops through until the end
var dataRecipe = listofWorkbooks.getDataRange().getValues();
for(var x=0; x<dataRecipe.length; x++)
{
var urlName = dataRecipe[x][0];
getListofTabs(urlName);
}}```
You should get rid of appendRow() in the for loop.
In order to do that you need to create an empty array before the for loop and then push() the new values into this array. Then after the for loop, use setValues() to add the values to the sheet. In this way, you call setValues() once instead of calling appendRow() tabs.length number of times.
For example the function getListofTabs(urlName) could be replaced by that:
function getListofTabs(urlName) {
var ssRecipeTable = SpreadsheetApp.openByUrl(urlName);
var dat = []
var tabs = ssRecipeTable.getSheets();
for(var i=0;i<tabs.length;i++){
sheetName = tabs[i].getName();
sheetID = tabs[i].getSheetId();
sheetURL = tabs[i].getParent().getId();
//Logger.log(sheetName,sheetID,sheetURL);
dat.push(['=HYPERLINK("https://docs.google.com/spreadsheets/d/'+tabs[i].getParent().getId()+'/edit#gid='+tabs[i].getSheetId()+'","'+tabs[i].getName()+'")',tabs[i].getName(),tabs[i].getParent().getId(),tabs[i].getSheetId()]);
}
dataList.getRange(dataList.getLastRow()+1,1,dat.length,dat[0].length).setValues(dat);
}
Please read carefully the best practices when writing GAS.

Creating New Spreadsheets from Spreadsheet

I am creating a sheet that can create a series of sheets that interact to help run a simulation. Part of this project involves creating a series of sheets- individual score sheets- that can only be accessed by single players in the game. The code I'm hoping to use is below, but I'm running into a series of issues. The first is thatit says I don't have permission to run SpreadsheetApp.create. I have spent about an hour looking around online for how to cure this, but just don't understand it and can't find a good answer. The second, and potentially broader issue, is that it seems incredibly complicated to use GAS to interact with different spreadsheets (i.e. not within the same spreadsheet). At a later point in the project, we will have to retrieve information from these sheets, etc. and if it is going to be difficult to do through scripts, may have to think of a workaround.
/** #OnlyCurrentDoc */
function individualSheets(){
var playerarray = playerArray();
var spreadsheet = SpreadsheetApp.getActive();
var spreadsheetlinks = []
//creates individual sheet for each player, then adds the link of their sheet to a list
for(i=0;i<playerarray.length;i++){
var spreadsheetname = playerarray[i];
var newspreadsheet = SpreadsheetApp.create(spreadsheetname);
spreadsheetlinks.push(DriveApp.getUrl(newspreadhseet));
}
//pasting the links of each player in the appropriate sheet
for(i=0;i<spreadsheetlinks.length;i++){
spreadsheet.setActiveSheet("PlayerInfo").getRange('D'+(i+1)).activate()
spreadsheet.getCurrentCell.setValue(spreadhseetlinks[i])
}
}
Apps Script doesn't have difficulty to use several Spreadsheets in the same script.
I would add another array to store the Ids, so you won't have to get them from the urls:
var spreadsheetlinks = []
var spreadsheetIds = [];
//creates individual sheet for each player, then adds the link of their sheet to a list
for(i=0;i<playerarray.length;i++){
var spreadsheetname = playerarray[i];
var newspreadsheet = SpreadsheetApp.create(spreadsheetname);
spreadsheetlinks.push(DriveApp.getUrl(newspreadhseet));
spreadsheetIds.push(newspreadsheet.getId);
}
You can open the Spreadsheets using openById, so you can use an unlimited amount of them:
var sprSheet1 = SpreadsheetApp.openById('id 1');
var sprSheet2 = SpreadsheetApp.openById('id 2');
var sprSheet3 = SpreadsheetApp.openById('id 3');
...
or even better:
var sprSheets = [];
for (var j = 0; j < spreadsheetIds.length; j++){
sprSheets.push(SpreadsheetApp.openById(spreadsheetIds[j]);
}
Regarding the SpreadsheetApp.create issue, make sure you authorized the needed scopes:
Scripts that use this method require authorization with one or more of
the following scopes:
https://www.googleapis.com/auth/spreadsheets.currentonly
https://www.googleapis.com/auth/spreadsheets
You can check them in Apps Script View > Manifest file. If you never touched this, they won't show up. You can add them manually:
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/drive.file"
]
In case you still get the permission issue when creating the Spreadsheet, you might want to check the playerArray function to see if it's actually returning a String.

Google apps script for sheets, how to create a 2-way link between two spreadsheets?

I'm attempting to write a script to continuously update two spreadsheets so that the information put in one always goes into the other.
The full project is to create a master spreadsheet with 50 people on it and each one of them has their own sheet/page, however they aren't allowed to access this master sheet as they are not allowed to see the other peoples data. (I am currently unaware of any viewing permission commands but I'm pretty sure there aren't any).
So the solution that I have been considering is creating 50 other spreadsheets and each of them will have a single sheet with all of the same information as the master Spreadsheet and the name of the sheet will be the same as on the master page.
I found this code on another post that was for a similar problem
function onEdit(e) {
// Get the event object properties
var range = e.range;
var value = e.value;
//Get the cell position
var row = range.getRowIndex();
var column = range.getColumnIndex();
exportValue(row,column,value)
}
function exportValue(row,column,value) {
var ss = SpreadsheetApp.openById(targetID);
var s = ss.getSheetByName(targetSheetName);
var target = s.getRange(row, column);
target.setValue(value);
}
in this I understand what everything is doing except the ("var range = e.range; var value = e.value;") lines, is ths what im looking for or not, idk
Thanks in advance
:)

Random string generator randomizing too often

I'm looking for input on a small random string generator project.
I'm trying to create a random string generator that puts three words together, where I can then save strings that I like to another sheet.
I'm using a basic script to assign a RANDBETWEEN formula to 3 specific cells, which works great to generate the strings, but it keeps recalculating with each additional step in the script it seems. I'd like to run one function then if I like the string I would run another function to store the string. However, when I try that it has already recalculated the RANDBETWEEN formulas and it saves something completely different.
I have an example sheet here:
https://docs.google.com/spreadsheets/d/1TWziyjjLQJJApkHCqrLzNGMFU0sf-vNEOOSatuhHURo/edit?usp=sharing
And here is the code I'm using for the "Go" and "Save" buttons, respectively:
function generateString() {
var ss = SpreadsheetApp.openById('1b9rP39sgZDOZqu7AmZhOxX9J8CMukmUw7NPY3Qzuq78');
var sheet = ss.getSheetByName('Randomizer');
var cell = sheet.getRange('D4');
var cell2 = sheet.getRange('E4');
var cell3 = sheet.getRange('F4');
cell.setValue('=INDEX(A:A,RANDBETWEEN(1,counta(A:A)))');
cell2.setValue('=INDEX(A:A,RANDBETWEEN(1,counta(A:A)))');
cell3.setValue('=INDEX(A:A,RANDBETWEEN(1,counta(A:A)))');
var cell4 = sheet.getRange('P4');
cell4.copyTo (sheet.getRange ('P5'), {contentsOnly: true}); //an attempt to paste values to record the random string
}
function saveString() {
var ss = SpreadsheetApp.openById('1b9rP39sgZDOZqu7AmZhOxX9J8CMukmUw7NPY3Qzuq78');
var sheet = ss.getSheetByName('Randomizer'); //replace with source Sheet tab name
var range = sheet.getRange('P4'); //assign the range you want to copy
var data = range.getValues();
var tss = SpreadsheetApp.openById('1b9rP39sgZDOZqu7AmZhOxX9J8CMukmUw7NPY3Qzuq78');
var tsheet = tss.getSheetByName('Saved Strings'); //replace with destination Sheet tab name
tsheet.getRange(tsheet.getLastRow()+1, 1, 1, 1).setValues(data);
}
Please let me know if anyone has some ideas on how to make this work properly. Thanks!
RANDBETWEEN the same as RAND are volatile functions. That means that their results changes every time that spreadsheet is recalculated.
If you need to keep the randomized to result be "freezed" for a while instead of this functions one alternative to consider is the use of a custom function as they are recalculated only when at least one of its arguments changes.
Related
Refresh data retrieved by a custom function in Google Sheet

set newly created google sheet as the active sheet

I am using google sheets to import data into a mysql database. Each month a new sheet gets created for instance 06_2017. Is there a way to set the newly created sheet as active sheet or based on current month & year set that sheet as active. Instead of having to hard code
var gsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('06_2017');
var gsheetname = sheet.getSheetName();
var gdata = sheet.getDataRange().getValues();
As #Cooper have said, you can store the name of the newly created sheet in UserProperties, then place your code in onOpen() method of your script.
You can do it like this,
function onOpen(e)
{
var prop = PropertiesService.getDocumentProperties();
var sheet_name = prop.getProperty(<NAME_OF_SHEET>);
var sp = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheet_name).activate();
}
If you are going to stick to the pattern 'MM_YYYY' for naming your sheets, the following code will always activate the sheet with the latest date. If your plan is to use different naming patterns in a single document, you need to refactor the code below to allow for this.
The onOpen() function is one of the so-called simple triggers in GAS, so every code inside this function will be executed when you open the document. The sort() method will sort array elements based on given criteria. Since sort() doesn't know what criteria you'd like to use for sorting Sheet objects, you need to pass a comparator function to override the default one.
The comparator function parses sheet names and creates date objects by passing year and date (in that order) to the new Date() constructor. It then uses the result of date subtraction to sort the 'sheets' array in descending order, from the highest to the lowest value.
Finally, you take the first element of the sorted array (that would be the latest created sheet) and set it as the active sheet.
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
sheets.sort(function(a,b) {
var arr1 = a.getName().split("_");
var arr2 = b.getName().split("_");
return new Date(arr2[1], arr2[0]) - new Date(arr1[1], arr1[0]);
});
if (sheets.length < 1) {
return;
}
ss.setActiveSheet(sheets[0]);
}