Adding rows based on a few variables - google-apps-script

I'm looking for a function that can get inputs like - "project", "locale", "date" and the function will go to the relevant sheet in the spreadsheet based on the "project" value and will show the relevant rows based on the locale and date.
For example -
Spreadsheet X includes 3 sheets - Project 1, project 2 & summary.
In the summary sheet, I have 3 variables - project, locale & date. I also have a button of "show".
Once I'll click on the "show" the function will show me the data according the variables.

Here's a simple example that I think may be close to what you want. It includes a search button and a clear button and expects you to select a cell on the row of the summary table that you desire to see the data of. After selecting a row on the summary table you click the search button and the data from that project page for that location and date will be display on the side bar. If you wish to clear the data then press the clear button.
Code.gs:
function searchForDataSideBar()
{
var ui=HtmlService.createHtmlOutputFromFile('searchinfordata');
SpreadsheetApp.getUi().showSidebar(ui);
}
function searchForData()
{
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Summary');
var cell=sh.getActiveCell();
var row=cell.getRow();
var cols=sh.getLastColumn();
var rg=sh.getRange(row, 1, 1, cols);
var vA=rg.getValues();
var sh1=ss.getSheetByName(vA[0][0]);
var rg1=sh1.getDataRange();
var vA1=rg1.getValues();
var s='';
for(var i=1;i<vA1.length;i++)
{
var data=vA1[i];
var a=vA[0][1];
var b=data[0];
var c=vA[0][2].valueOf();
var d=data[1].valueOf();
if(a==b && c==d)
{
s+=Utilities.formatString('Project Name:%s<br />Location:%s<br />Date:%s<br />Data1:%s<br />Data2:%s</br>Data3:%s</br>Data4:%s</br>Data5:%s</br><hr>',vA[0][0],data[0],Utilities.formatDate(new Date(data[1]), Session.getScriptTimeZone(), "E MMM dd,yy"),data[2],data[3],data[4],data[5],data[6])
}
}
return s;
}
I used a sidebar to put the buttons on and to display your data. The name of my file was searchinfordata.html:
<!DOCTYPE html>
<html>
<head>
<title>Searching for Data</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
function search()
{
google.script.run
.withSuccessHandler(found)
.searchForData();
}
function found(hl)
{
document.getElementById('found').innerHTML=hl;
}
function clearDiv()
{
document.getElementById('found').innerHTML='';
}
console.log('MyCode');
</script>
</head>
<body>
<div id="instr">Please Select a cell on the row in the summary tab that you wish to see the data for.</div>
<input type="button" value="Search" onClick="search();" />
<input type="button" value="Clear" onClick="clearDiv();" />
<div id="found"></div>
</body>
</html>
And here's the onOpen() function where you can build your menu or launch your sidebar.
function onOpen()
{
SpreadsheetApp.getUi().createMenu('My Tools')
.addItem('Show Sidebar','searchForDataSideBar')
.addToUi();
searchForDataSideBar();//launches your sidebar whenever you open your spreadsheet.
}
This is what the Summary Tab looks like:
P1 Tab:
P2 Tab:
P3 Tab:
And Finally the Sidebar:

Related

add values moving down column in google sheets using apps script

In google sheets I have an input field for names that pops up when you press a button. I want all the names to appear in column B starting at cell B44. The names will continue to move down the column as you use the input field to add more names (B44, B45, B46...).
First I tried using appendRow, however I realized you can't specify a starting cell. I'm now using setValue and getRange('B44'). The problem with this is that each time you enter a new name into the input field it just replaces the last name and stays in cell B44.
code.gs
function addminitask() {
var html = HtmlService.createTemplateFromFile('minitask').evaluate()
var result = SpreadsheetApp.getUi().showModalDialog(html, ' ');
SpreadsheetApp.getActive().toast(result);
}
function AddRecord(name) {
var ss= SpreadsheetApp.getActiveSpreadsheet();
var mainSheet = ss.getSheetByName("DAILY HUB");
mainSheet.getRange('B44').setValue([name]);
}
function startForm()
{
var form = HtmlService.createHtmlOutputFromFile('minitask');
SpreadsheetApp.getUi().showModalDialog(form, 'Add Record');
}
function onOpen(e)
{
addMenu();
}
minitask.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function AddRow()
{
var name = document.getElementById("name").value;
google.script.run.AddRecord(name);
}
</script>
</head>
<body>
Name: <input type="text" id="name" />
<input type="button" value="Add" onclick="AddRow()" />
</body>
</html>
In your script, how about the following modification?
From:
mainSheet.getRange('B44').setValue([name]);
To:
var values = mainSheet.getRange('B44:B').getDisplayValues();
var idx = values.findIndex(([b]) => !b);
var lastRow = (idx == -1 ? values.length : idx) + 44;
mainSheet.getRange(`B${lastRow}`).setValue(name);
By this modification, the value is put in the 1st empty cell below cell "B44".

How can I create a web app where I can read text from a sheet based on dropdown selections?

I am trying to create a role description generator which reads pre-written text from a Google Sheet and assembles it in blocks in a web app through selections (team, role, seniority level, etc.) in dropdown menus.
This is an example of what the data in the sheet looks like:
Team name
Team description
A-team
Description
B-team
Description
...
...
So far, for the team selection, I have created the dropdown menu which reads the data from the sheet, and pulls the names of each team into a dropdown list. But my problem is loading the corresponding team description text into the HTML page. I just can't seem to get it to work.
When pressing the generate button, what should happen is that the description for A-team is loaded, but instead I get [object MouseEvent].
Any suggestions? Thanks in advance! :)
Here's my code:
Code.gs
var url = "*spreadsheet URL*";
function doGet(e) {
return HtmlService.createTemplateFromFile('index')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
//get the data for the dropdown list
function valuesForList(list) {
//define the data
var ss = SpreadsheetApp.openByUrl(url)
var teamsSheet = ss.getSheetByName('Data');
var lastRow = teamsSheet.getLastRow();
var teamsRange = teamsSheet.getRange(1, 3, lastRow, 1);
//create a named range
ss.setNamedRange('teamsList', teamsRange);
//get the values from the range
var listValues = ss.getRangeByName(list).getValues();
return listValues;
}
//the function to show the data on the index.html
function PostInfo (userInfo){
//load the data
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Teams");
var data = ws.getRange(2,1,ws2.getLastRow(),2).getValues();
var teamList = data.map(function(r){ return r[0]});
var teamDesc = data.map(function(r){ return r[1]});
var position = teamList.indexOf(userInfo.teams);
if(position > -1){
return teamDesc[position];
} else {
return "Unavailable";
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?>
<script>
function onListSuccess(list) {
var listLength = list.length;
for (i=0; i<listLength;i++) {
var dropdown = document.getElementById("teams");
var opt = document.createElement("option");
dropdown.options.add(opt);
opt.text = list[i][0];
opt.value = list[i][0];
}
}
function onListSelect(teamDesc){
var text = teamDesc.toString().split(",");
document.getElementById('est').innerHTML = text;
}
</script>
</head>
<body>
<div id="main">
<h1>Role Description Generator</h1>
<p>
<label for="teams">Team:</label>
</p>
<p>
<select name="teams" id="teams" tabindex="2"></select>
</p>
<button id="btn">Generate</button>
<div>
<label for="est">Team description:</label>
<p id="est" name="est"></p>
</div>
</div>
</body>
<script>
function populateList(){
google.script.run.withSuccessHandler(onListSuccess).valuesForList('teamsList');
}
document.getElementById("teams").addEventListener("change", doStuff);
document.getElementById("btn").addEventListener("click", onListSelect);
function doStuff(){
var userInfo = {};
userInfo.teams = document.getElementById("teams").value;
google.script.run.PostInfo(userInfo);
}
window.addEventListener('load', populateList);
</script>
</html>
Modification points:
In your script, when the dropdown list is changed, doStuff() is run. But in this case, google.script.run.PostInfo(userInfo) runs only the function of PostInfo at Google Apps Script. By this, the returned value is not used.
And, when the button is clicked, onListSelect is run. But in this case, teamDesc of onListSelect(teamDesc) is the event object. By this, such value of [object MouseEvent] is shown. I thought that this might be the reason of your issue.
By the way, when I saw your Google Apps Script, I noticed that PostInfo has a modification point. When var data = ws.getRange(2,1,ws2.getLastRow(),2).getValues(); is run, I think that an error occurs. Because ws2 is not declared. In your case, is that ws? I thought that this might be due to your miscopy.
When you want to show the value from PostInfo when the button is clicked, how about the following modification?
Modified script:
HTML&Javascript side:
From:
document.getElementById("teams").addEventListener("change", doStuff);
document.getElementById("btn").addEventListener("click", onListSelect);
function doStuff(){
var userInfo = {};
userInfo.teams = document.getElementById("teams").value;
google.script.run.PostInfo(userInfo);
}
To:
document.getElementById("btn").addEventListener("click", doStuff);
function doStuff(){
var userInfo = {};
userInfo.teams = document.getElementById("teams").value;
google.script.run.withSuccessHandler(onListSelect).PostInfo(userInfo);
}
Google Apps Script side:
From:
var ws = ss.getSheetByName("Teams");
var data = ws.getRange(2,1,ws2.getLastRow(),2).getValues();
To:
var ws = ss.getSheetByName("Teams");
var data = ws.getRange(2,1,ws.getLastRow(),2).getValues();
Note:
In this modidication, it supposes that the Google Apps Script works fine and returns the correct values. Please be careful this.
Reference:
Class google.script.run

Populate Google Form using Google App Script on Form open

I have a google form to where I want to populate with some data from a spreadsheet when user is opening the form.
I have a ListItem which I populate it with spreadsheet data. Until now I used the Open(e) function and a trigger, but I just found out that this method is triggered only on form edit not on form open.
Do you have an idea how can I do that?
To have an idea on what I want, I have two files, Code.gs contains the main functions like onOpen and onFormSubmit, and ItemClass where I get my data and create the UI.
I set a console log to Open(e) function, but never triggers.
Code.gs
function onOpen(e) {
console.log({message: 'onOpen', initialData: e});
let items = getItems();
let form = FormApp.openById(PARAMS.formID);
form.setTitle('New Form')
createUI(form, items);
}
ItemsClass.gs
function getItems() {
var email = Session.getActiveUser().getEmail();
var allItems = SpreadsheetApp.openByUrl(PARAMS.sheetURL).getSheetByName("Items Stream").getDataRange().getDisplayValues();
var headers = allItems.shift();
var items = new Array;
for (var i = 0; i < allItems.length; i++) {
var first = allItems[i][1]
var second = allItems[i][2]
items.push(first + "&" + second)
}
return items;
}
The on Open trigger Google Forms works only when opening the form editor, not the actual form that the user fills out
To return to the user the updated data whenever he opens the form and allow him to modify the data, you should create a custom HTML form with Web polling.
Web Polling with setInterval allows to pull fresh data from the spreadsheet and update it in specified intervals
Apps Script WebApps allow you to combine Apps Script and HTML/Javascript which allows you easy interaction between serverside and UI - useful for creation of a custom HTML form
Use google.script.run to communicate between the two sides.
Simple sample pulling updated data from column A in a spreadsheet and allowing the user to modify the values:
code.gs:
var sheet = SpreadsheetApp.openById('XXX').getSheetByName("YYY");
function doGet(){
var html=HtmlService.createTemplateFromFile('index');
return html.evaluate();
}
function getValues() {
//get data from the first column
var data = sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues();
var table = "";
for (var i = 0; i < data.length; i++) {
table +='<tr><td>' + data[i][0] + ' </td><tr>';
}
return table;
}
function writeToSheet(newValues) {
newValues = newValues.split(",");
var range = sheet.getRange(1, 1, newValues.length, 1);
newValues = newValues.map(function(row){return [row]});
range.setValues(newValues);
}
index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<script>
function onSuccess(values){
document.getElementById("data").innerHTML=values;
}
function polling(){
//modify the interval of 2000 ms to any desired value
setInterval( function(){google.script.run.withSuccessHandler(onSuccess).getValues()},2000);
}
function updateValues(){
var newValues= document.getElementById("newValues").value;
google.script.run.writeToSheet(newValues);
}
</script>
<body onload="polling()">
<div> Values: </div>
<table id="data">
</table>
<div> If you want to modify the values in the spreadsheet, type in new values comma separated: </div>
<input type="text" id="newValues" ><br><br>
<input type="button" value="Confirm" onclick="updateValues()">
</body>
</html>
Deploy this WebApp and described in the documentation and paste the WebApp URL into a browser address bar.

Auto Send Emails Depending on Dropdown Menu Choice in Google Form

I am a complete beginner when it comes to code and script. I'm trying to get my form to send and email to specific people depending on a response on a drop down menu.
Example: Pete is working on Project A, so they select Project A on a drop down menu asking what project they are working on.
If Pete selects Project A, I need a response to go to Persons A,B and C.
Now if Jessica is working on Project B, I need a response to go to persons A,B and D
Is this possible? Did I explain this properly? Am I completly dense and it's simple?
I offer this simple example just to give you a start. Take a close look at it. Use the online documentation to figure out what it does. In the G-Suite Services you'll find information about Gmail and how to use it. Plus there are numerous examples on this site pertaining to email.
Google Script:
function getSelectOptions(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Selections')
var rg=sh.getDataRange();
var selections=[];
var vA=rg.getValues();
for (var i=0;i<vA.length;i++){
selections.push(vA[i][0]);
}
return selections;
}
function getEmailsForChoice(choice){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Selections')
var rg=sh.getDataRange();
var vA=rg.getValues();
for (var i=0;i<vA.length;i++){
if(choice==vA[i][0]){
var emails=Utilities.formatString('%s;%s;%s',vA[i][1],vA[i][2],vA[i][3]);
break;
}
}
return emails;
}
function showMyDialog(){
var ui=HtmlService.createHtmlOutputFromFile('choices')
SpreadsheetApp.getUi().showModelessDialog(ui, 'Choices');
}
choices.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
window.onload=function(){
google.script.run
.withSuccessHandler(updateSelect)
.getSelectOptions();
}
function updateSelect(vA){
var select = document.getElementById("sel1");
//select.options.length = 0;
for(var i=0;i<vA.length;i++)
{
select.options[i] = new Option(vA[i],vA[i]);
}
}
function savSelect(){
var selected=document.getElementById('sel1').value;
google.script.run
.withSuccessHandler(function(emails){
console.log(emails);
document.getElementById('emails').innerHTML='Send Emails to the following: '+emails;
})
.getEmailsForChoice(selected);
}
console.log('My Code');
</script>
</head>
<body>
<div id="emails"></div>
<select id="sel1" onChange="savSelect();"></select>
</body>
</html>
This is what my spreadsheet looks like:

Using Google AppScript, Is it possible to programmatically publish to the web a _single sheet_ within a Google Sheets document?

I would like, through Google Appscript, to (a) programmatically publish to the web selected sheets within a Google Sheets document, (b) obtain programmatically the URL where each sheet is published, and (c) have the published version of each sheet automatically update whenever the corresponding sheet is updated (this should happen automatically, right?). Right now, I can accomplish this only through File/Publish to Web...
The following question and answer is highly related to this question:
Google Sheets API: How to "publish to web" for embeddable sheet?
However, it appears to apply only to publishing an entire Google Sheets document, not a single sheet within a Google Sheets document. Any solution ideas would be most appreciated.
I have gained some insight into this question. It is possible to obtain a URL to a published HTML version of a single sheet in a Google Sheets document simply by modifying the URL used to access that sheet.
For example, here is the URL of a sheet I'm working on in Google Sheets, copied directly from my browser's URL bar:
https://docs.google.com/spreadsheets/d/1fTx3dUsvdbVKgP2nXs1LcyG_7oBp-MoFZTXn7MtdEZg/edit#gid=1711661074
I can then modify the URL as follows to get a published HTML version of that single sheet:
https://docs.google.com/spreadsheets/u/0/d/1fTx3dUsvdbVKgP2nXs1LcyG_7oBp-MoFZTXn7MtdEZg/htmlembed/sheet?gid=1711661074
Summary of URL modifications I made:
Replace "/d" after "spreadsheets" with "/u/0/d"
Replace "edit#" with "htmlembed/sheet?"
Other inferences one can make:
The long string after "/u/0/d" is the ID of the Google Sheets document.
The shorter string after "sheet?" is the ID of the single sheet within that document.
These new insights transform my question into a new one: namely, how can I programmatically obtain (through Google Appscript) the ID of the Google Sheets document I'm working on, together with the ID of the spreadsheet I'm working on?
Here's the answer:
To get the ID of the current Google Sheets document within Appscript:
var ss = SpreadsheetApp.getActiveSpreadsheet().getId();
To get the ID of the current sheet within the current Google Sheets document:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getSheetId();
I can now build a URL for a published html version of any single sheet within a Google Sheets document through string concatenation as follows:
var publishedURL = "https://docs.google.com/spreadsheets/u/0/d/" + ss + "/htmlembed/sheet?gid=" + sheet;
There's still one lingering issue, though: It appears that users of this published URL must manually refresh the browser in order to sync the HTML with the spreadsheet. At the present time, I do not have a solution to this problem, other than to request that users of the URL install an auto URL refresher or manually refresh the page periodically. I'd welcome any ideas on this.
It looks like you can publish individual sheets according to these dialogs:
It does update the published sheets although I've noticed quite a bit of delay in the process occasionally.
Since the Publish to the Web simply shows a readonly version of an html table that contains sheet values then you could do that with one webapp. Here's an example below that displays all sheets in tabular form.
A Webapp to display all sheets:
function publishAllSheets()
{
var ss=SpreadsheetApp.getActive();
var allShts=ss.getSheets();
var s='All my Sheets';
for(var i=0;i<allShts.length;i++)
{
var sh=allShts[i];
var rg=sh.getDataRange();
var vA=rg.getValues();
s+=Utilities.formatString('Sheet: %s <br /><table border="1">',allShts[i].getName());
for(var j=1;j<vA.length;j++)
{
s+='<tr>';
for(var k=0;k<vA[j].length;k++)
{
s+=Utilities.formatString('<td>%s</td>', vA[j][k]);
}
s+='</tr>';
}
s+='</table>';
}
return s;
}
function showAllMySheets()
{
var ui=HtmlService.createHtmlOutputFromFile('allsheets').setWidth(1000);
SpreadsheetApp.getUi().showModelessDialog(ui, 'All My Sheets')
}
function doGet()
{
var ui=HtmlService.createHtmlOutputFromFile('allsheets');
return ui.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
allsheets.html
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(function(){
google.script.run
.withSuccessHandler(updateDiv)
.publishAllSheets();
});
function updateDiv(hl)
{
document.getElementById('c1').innerHTML=hl;
}
</script>
</head>
<body>
<div id="c1"></div>
</body>
</html>
Here's the code for getting any one of your sheets:
function getSheetNames()
{
var ss=SpreadsheetApp.getActive();
var allShts=ss.getSheets();
var shts=[];
for(var i=0;i<allShts.length;i++)
{
shts.push(allShts[i].getName());
}
return shts;
}
function getOneSheet(name)
{
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName(name);
var rg=sh.getDataRange();
var vA=rg.getValues();
var s='';
s+=Utilities.formatString('Sheet: %s <br /><table border="1">',sh.getName());
for(var j=1;j<vA.length;j++)
{
s+='<tr>';
for(var k=0;k<vA[j].length;k++)
{
s+=Utilities.formatString('<td>%s</td>', vA[j][k]);
}
s+='</tr>';
}
s+='</table>';
return s;
}
onesheet.html
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(function(){
google.script.run
.withSuccessHandler(updateSelect)
.getSheetNames();
});
function updateDiv(hl)
{
document.getElementById('c1').innerHTML=hl;
}
function updateSelect(vA)
{
var select = document.getElementById("sel1");
select.options.length = 0;
for(var i=0;i<vA.length;i++)
{
select.options[i] = new Option(vA[i],vA[i]);
}
}
function getSelectedSheet()
{
var name=$('#sel1').val();
google.script.run
.withSuccessHandler(updateDiv)
.getOneSheet(name);
}
console.log('MyCode');
</script>
</head>
<body>
<select id="sel1">
<option value="" selected></option>
</select>
<input type="button" value="Select" onClick="getSelectedSheet();" />
<div id="c1"></div>
</body>
</html>