embed html inside google sheet - google-apps-script

I want to display HTML at the top of my spreadsheet by creating an html element and putting it at the top of my spreadsheet sheet.
For example, if I created one large cell at the top of my sheet by merging A1:G5, would it be possible to embed html within it:
<div>
<h1>"Hello World"?</h1>
</div>
I notice from within script editor you can go file > new > html file.
But I don't really get it's purpose.
I just tried this:
From script editor new script:
function addSomeHTML() {
var html = HtmlService.createHtmlOutputFromFile('cabbages')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
Cabbages is an html file:
<div>
<h1>Hello, world!</h1>
</div>
I then saved and navigated to my sheet. I selected a cell and typed =addSomeHTML()
The "loading" message appeared then an empty cell was shown. I was hoping to see "Hello World!" within the cell.
I've looked at the following documentation:
https://developers.google.com/apps-script/guides/html/templates#printing_scriptlets
https://developers.google.com/apps-script/guides/dialogs

You can use either a Modal or Modeless dialog box.
The Modal dialog uses the showModalDialog() method of the Ui Class.
Guide to Dialogs
Google Documentation - Modal Dialog
Add a custom menu to the spreadsheet
// This will run when the spreadsheet is opened or the browser page is refreshed
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Custom Menu')
.addItem('Open Dialog Box', 'openDialog')
.addToUi();
}
Create the function that runs from the menu
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('index');
SpreadsheetApp.getUi()
.showModalDialog(html, 'Correct Postcode Errors');
}
index.html
<div>
<h1>"Hello World"?</h1>
</div>

Related

Redirecting a web app to Sheets (script apps)

I have created a web app with the apps script however I am having a problem.
I have several links in a menu to navigate in the application and I have another link that goes to a Sheets file.
I would like this link to open in a new tab in my browser. And this is where I encounter my problem. The Sheets opens in a new tab but I get the following error message in the web app :
"Unsafe attempt to initiate navigation for frame with origin 'https://script.google.com' from frame with URL 'https://n-psool6bzsn7nbbxcwije73kogaweb6gvevl5w2i-0lu-script.googleusercontent.com/userCodeAppPanel'. The frame attempting navigation of the top-level window is sandboxed with the 'allow-top-navigation-by-user-activation' flag, but has no user activation (aka gesture)"
And when I click on another link, the Sheets opens in the same tab.
Here is the JS that opens the Sheets in a new tab :
function sheets(){
var url = document.getElementById("url").value;
var link = document.createElement('a');
link.href = "https://docs.google.com/spreadsheets/d/1oATOMdL5HdCx87YjPS79DVvZee_s6y5_J3t9oloYeZI/edit#gid=0";
link.id = 'linkURL';
window.open(document.body.appendChild(link));
document.getElementById("linkURL").click();
}
Here is the beginning of one of the html pages (the navigation bar is identical for all pages :
<nav id="navigation" class="navbar navbar-expand-lg navbar-dark ">
<div class="collapse navbar-collapse" id="navbarNav">
<input type="button" class="buttonNav" id="buttonSelected" value="Page 1"/>
<input type="button" class="buttonNav" id="button" value="Page 2" onclick="formulaire()"/>
<input type="button" class="buttonNav" id="button" value="Page 3" onclick="archives()"/>
<input type="button" class="buttonNav" id="button" value="Sheet" onclick="sheets()"/>
</div>
<?var url = getUrl();?><input type="hidden" value="<?= url ?>" id="url"/>
</nav>
And here is the apps script code:
function doGet(e){
if(!e.parameter.page){
return render('Index');
}
else if(e.parameter['page'] == 'Formulaire'){
var htmlOutput = HtmlService.createTemplateFromFile('Formulaire');
return htmlOutput.evaluate();
}
else if(e.parameter['page'] == 'Index'){
var htmlOutput = HtmlService.createTemplateFromFile('Index');
return htmlOutput.evaluate();
}
else if(e.parameter['page'] == 'Archives'){
var htmlOutput = HtmlService.createTemplateFromFile('Archives');
return htmlOutput.evaluate();
}
}
function getUrl(){
var url = ScriptApp.getService().getUrl();
return url;
}
I saw this post but i don't know how can i apply its in my dev.
Thank you for your help.
In your situation, how about the following modification? In this modification, your function of sheets() is modified as follows.
Modified script:
function sheets() {
var url = "https://docs.google.com/spreadsheets/d/1oATOMdL5HdCx87YjPS79DVvZee_s6y5_J3t9oloYeZI/edit#gid=0";
window.open(url, "_blank");
}
When sheets() is run, the URL is opened as a new tab.
Note:
When you modified the Google Apps Script of Web Apps, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in my report "Redeploying Web Apps without Changing URL of Web Apps for new IDE (Author: me)".
Reference:
Window.open()

google apps script : a select drop down list in google sheet

I have begun using google apps script in google sheets, and i want to create a dialogue box where the user will write an input that I will use later. the dialogue box shold have a drop list that will make suggestions or complete the input.
For anyone arriving here through a Google Search:
Drop downs in Google Sheets can be achieved with data validation. Create a column of entries. Let's say like this:
A4 = Apples
A5 = Tigers
A6 = Coriander
A7 = Forest
Then select a cell, say, B4. Now go to Data in the top menu. Choose Data validation. A module will open with options. Choose "List from a range." as criteria, then enter A4:A7 as the range. You will have the option to reject other input. Now hover over B4 and click the arrow. You will see that you now have an inline dropdown menu. It may be useful to know that you can add list sources an another tab and even hide that tab to users to keep the interface clean.
Now, to answer your actual question.
You want a dropdown to appear in a popup. This can be done! It's not as fast as using an inline dropdown with data validation, but it's much fancier.
Assuming you know at least the basics of Google Apps Script, here's the code:
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Custom Menu')
.addItem('Multiple choice', 'dropDownModal')
.addToUi();
}
function dropDownModal() {
var htmlDlg = HtmlService.createHtmlOutputFromFile('dropdown.html')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(350)
.setHeight(175);
SpreadsheetApp.getUi()
.showModalDialog(htmlDlg, 'A Title Goes Here');
};
function writeChoice(selection) {
const writeResponseLocation = "B4";
SpreadsheetApp
.getActiveSpreadsheet()
.getSheets()[0]
.getRange(writeResponseLocation)
.setValue(selection);
}
Then create a file called dropdown.html (in addition to the code.gs file above) and input the following:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<script>
function onSuccess() {
google.script.host.close();
}
function submit() {
const choice = document.getElementById('choice').value;
google.script.run
.withSuccessHandler(onSuccess)
.writeChoice(choice);
}
function setup() {
const button = document.getElementById('submitbutton');
button.addEventListener("click", submit)
}
</script>
<body onload="setup()">
<p>
There will be a slight delay on submission.
</p>
<form>
<select id="choice">
<option value="apple">Apple</option>
<option value="banana">Banana</option>
<option value="coriander">Coriander</option>
<option value="monkey">Monkey</option>
</select>
<button id="submitbutton">Submit</button>
</form>
</body>
</html>
Now save everything and reload the sheet. A menu will appear at the end of the menu bar called Custom Menu. Select that and choose Multiple choice. You'll have to give yourself permission to the run the code you entered for this to work (then choose the menu option again). That'll do it. Tweak the code to suit your needs.

Creating a dialogue box to capture booking details in Google sheets App Script

I am using Google sheets with app script to build a reservations chart for a hotel
Can someone please tell me if there is a way to add a Dialogue box to a google sheet that can ask multiple questions? I have found the Prompt Dialogue box but that seems to allow only one text box for data entry. I have something like this
var result = ui.prompt(
"Let's get to know each other!",
"Please enter your name:",
ui.ButtonSet.OK_CANCEL
);
// Process the user's response.
var button = result.getSelectedButton();
var text = result.getResponseText();
if (button == ui.Button.OK) {
// User clicked "OK".
ui.alert("Your name is " + text + ".");
} else if (button == ui.Button.CANCEL) {
// User clicked "Cancel".
ui.alert("I didn't get your name.");
} else if (button == ui.Button.CLOSE) {
// User clicked X in the title bar.
ui.alert("You closed the dialog.");
}
If there isnt something pre-built, can you please recommend how else I can capture data which would then feed a second sheet within the same spreadsheet .
many thanks
You need to use the HTML service
The method you are using is quite limited. To go further than that you would need to create your own HTML file and serve it from Apps Script. The flow of that is:
Create an HTML file in the script editor
Create your HTML form
Write a script on the HTML that calls a function on your gs script.
Sample code
Code.gs
// Creates form on UI
function form() {
var htmlOutput = HtmlService
.createHtmlOutputFromFile('form')
.setWidth(250)
.setHeight(300);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Add your info');
}
// Uses info passed from rendered HTML to add data to sheet.
function addForm(data){
console.log(data)
SpreadsheetApp.getActiveSpreadsheet().getRange("A1:C1").setValues([data])
}
form.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// function to run when server-side script is successful
function onSuccess(){
google.script.host.close()
}
// function to run when form is submitted
function sendForm(){
console.log("RUNNING")
let name = document.getElementById("name").value
let country = document.getElementById("country").value
let DOB = document.getElementById("DOB").value
let data = [name, country, DOB]
// call server side function
google.script.run.withSuccessHandler(onSuccess).addForm(data)
}
</script>
</head>
<body>
<form id="form" onsubmit="sendForm()">
<label for="name">First name:</label><br>
<input type="text" name="name" id="name">
<label for="country">Country:</label><br>
<input type="text" name="country" id="country">
<label for="DOB">DOB:</label><br>
<input type="text" name="DOB" id="DOB">
<input type="submit">
</form>
</body>
</html>
Explanation
When the function form() is run from the script editor, it displays your HTML in the Spreadsheet UI.
This shows a form with three text inputs and a submit button.
The submit button has a onsubmit="sendForm()" which is a function defined within the HTML.
It gets all the info from the form, and then calls google.script.run.withSuccessHandler(onSuccess).addForm(data). This is an asynchronous function that sends a request to the gs file to run the addForm function and then when successful, to run the onSuccess function in the HTML.
The onSuccess simply closes the form.
addForm adds the info to a range in the spreadsheet.
Reference
HTML service
Show Modal Dialog
google.script.run

Creating a function to input data into spreadsheet via message dialogue.

Complete newcomer to programming here. I'm a little lost.
This is for a character database for an online tabletop rpg group. I'm trying to create a function that will open up a text dialogue that will:
Ask which players participated
How much gold and exp were earned
The function then needs to find the rows associated with the entered player names and add the gold and exp values to pre-existing values.
You need to implement following steps,
Override onOpen() method to add a custom menu in the Spreadsheet. Add
a submenu under it. On clicking this sub menu a HTML form will be
opened.
Design a HTML page with all required inputs and invoke this
HTML page from submenu click suggested in the step 1. Add a button in
this HTML page.
On click event of the button suggested in step 2
write a method which will perform search and insert operation in
Excel file.
Sample snippet for all 3 steps,
Appscript code
function onOpen() {
var ui = SpreadsheetApp.getUi();
// Or DocumentApp or FormApp.
ui.createMenu('Filter')
.addItem('Set Filter', 'menuItem1')
.addToUi();
}
function menuItem1() {
fetchForm();
}
function fetchForm() {
var html = HtmlService.createHtmlOutputFromFile('index')
.setWidth(530)
.setHeight(540)
.setSandboxMode(HtmlService.SandboxMode.NATIVE);//index is HTML filename
SpreadsheetApp.getUi().showModalDialog(html, 'Create New Rule');
}
function processForm(myForm) {
Logger.log("INFO: Received data: "+myForm.inboxVal);
}
index.html
<form class="form-style-7" id="myForm">
<ul>
<li>
<label for="inbox">Inbox Filter</label>
<input type="text" id="inboxVal" name="inboxVal" maxlength="100">
<span>Enter Inbox Search Criteria Here</span>
</li>
<li>
<input type="button" value="Create Rule" onClick="google.script.run.withSuccessHandler().processForm(this.form)">
</li>
</ul>
</form>
Hope this helps.

Reload Add On from Code

I have a google apps-script add-on which is loaded in the side bar of a Google Spreadsheet.
How does one reload an apps script add-on ones the user switches sheets or from button click ?
The simplest way to reload an ad-on is to start/launch it again from the add-on's menu - this will re-load the sidebar. Or you can add a button to your sidebar which runs google.script.run.showSidebar() (or whatever your server-side function for showing the sidebar is called).
Since add-ons only have access to simple triggers (onInstall(), onOpen() and onEdit()) and can't (yet) tell what a user does outside the add-on, you will have to write your own javascript function in the sidebar's html page to re-set the your add-on's user interface to default state (I assume that is what you mean by "reload"), i.e to reset all form fields to default values, remove any injected help/status text, etc etc.
To have this function execute on button click is not too hard - just trigger the function from the button's onclick event. With a bit more work you can even add a 'Reset' menu item in your add-on's menu that does the same thing.
To make such function run 'automatically' when user switches sheet is also possible, but will require polling for spreadsheet changes. Basically you can write a javascript function in your add-on's sidebar page that runs on a certain interval and calls a server-side function that checks if currently active sheet is same as before (which you can store in userProperties, for example). If the sheet is different, call your js function that resets the ui of your add-on + update the userProperty with the name of currently active sheet. Keep in mind that there will be a bit of delay between user switching sheets and your add-on running its reset code and reloading its ui - if that is an issue, then reloading the ui from button click is a better option.
Here is some sample code to give you an idea of what you can do. You can view the working spreadsheet here
Code.gs
function onOpen(e) {
// Add this add-on to Add-ons menu
SpreadsheetApp.getUi().createAddonMenu()
.addItem('Start / Reset', 'showSidebar')
.addToUi();
// save current active sheet name in user properties for later checking if user switched sheets
saveSheetNameToProperty();
};
function onInstall(e) {
onOpen(e);
};
function showSidebar() {
var ui = HtmlService.createHtmlOutputFromFile('Sidebar').setTitle('Add-on Reset Test');
SpreadsheetApp.getUi().showSidebar(ui);
};
/**
* Saves current active sheet name to user property lastActiveSheet
* #param String sheetname Name of sheet to save to user property. If undefined (not passed), saves current active sheet name.
*/
function saveSheetNameToProperty(sheetname) {
var sheetName = sheetname || SpreadsheetApp.getActiveSheet().getName();
PropertiesService.getUserProperties().setProperty("lastActiveSheet", sheetName)
};
/**
* Checks if user has switched sheets by comparing current active sheet name to name stored in user property
* #return Boolean True/False flag denoting if sheet was switched. True=sheet was switched; False=still on same sheet
*/
function checkSheetChanged() {
var sheetChanged = false;
var sheetName = SpreadsheetApp.getActiveSheet().getName();
var lastActiveSheet = PropertiesService.getUserProperties().getProperty("lastActiveSheet");
if (sheetName!=lastActiveSheet) {
sheetChanged = true;
saveSheetNameToProperty(sheetName);
// if you'd rather just reload the whole sidebar, then un-comment the line below and delete the return statement
// showSidebar();
}
return sheetChanged;
};
Sidebar.html
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<!-- The CSS package above applies Google styling to buttons and other elements. -->
<div class="sidebar branding-below">
<form id="addonForm">
<div class="block">
<label for="selectBox">Select a value:</label>
<select name="selectBox" id="selectBox">
<option value="" selected>Select a value...</option>
<option value="Value 1">Value 1</option>
<option value="Value 2">Value 2</option>
<option value="Value 3">Value 3</option>
</select>
</div>
<div class="block">
<label for="textBox">Enter some text:</label>
<input type="text" name="textBox" id="textBox" placeholder="Enter some text...">
</div>
<div class="block" id="button-bar">
<button type="button" class="blue" id="simpleResetBtn" onclick="resetForm(true);" title="I reset the sidebar's form controls to their default state">Reset form</button>
<button type="button" class="red" id="reloadAddonBtn" onclick="google.script.run.showSidebar();" title="I completely reload the sidebar - fresh start!">Reload add-on</button>
</div>
</form>
<div class="block" id="statusText" style="color:#666; margin-top:10px;"></div>
</div>
<div class="sidebar bottom">
<span class="gray branding-text">Reset Add-on Sample by Azadi</span>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
/**
* On document load, set up interval-based execution of checkSheetChanged() function to check if user has switched sheets
*/
$(function() {
// run checkSheetChanged() function every 5000 miliseconds
var sheetChecker = window.setInterval(checkSheetChanged, 5000);
});
/**
* Resets the form in the add-on's sidebar and shows status text.
* #param Boolean fromButtonClick Boolean flag denoting if form reset was triggered from button click or via timed script execution
*/
function resetForm(fromButtonClick) {
var buttonClick = fromButtonClick || false;
var form = $("#addonForm")[0];
var statusDiv = $("#statusText");
form.reset();
if (buttonClick) {
statusDiv.text("Addon UI has been reset from [Reset form] button click");
}
else {
statusDiv.text("Addon UI has been reset automatically via timed script following sheet switch");
}
};
/**
* Runs the checkSheetChanged() server-side function (in Code.gs) to check if user has switched sheets
* and executes checkSheetChangedCallback() function on success
*/
function checkSheetChanged() {
google.script.run.withSuccessHandler(checkSheetChangedCallback).checkSheetChanged();
};
/**
* Callback for checkSheetChanged() function.
* Resets the form in the sidebar if user has switched sheets.
* #param Boolean isDifferentSheet Boolean flag returned from server-side script. True=sheet was switched. False=user is still on same sheet.
*/
function checkSheetChangedCallback(isDifferentSheet) {
if (isDifferentSheet) {
resetForm();
}
};
</script>
Hope this helps!