I have some Google Sheets app script code that hits an API and updates a field in a sidebar based on some user input. Everything works as expected with the exception of the button used to trigger the API call from the sidebar. For some reason, clicking the button opens a new, blank tab in the browser.
My best guess is that I'm somehow implementing the google.script.run.withSuccessHandler() incorrectly but I've been unable to confirm this. Any help would be much appreciated.
Sidebar.html
This is the full sidebar file that I'm using.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(function() {
$('#narrative-from-selection').click(getNarrative);
});
function getNarrative(narrative) {
//document.getElementById('narrative-response').innerHTML = narrative.replace(new RegExp('\r?\n','g'), '<br />');
var projectName = $('#project-name').val();
var templateName = $('#template-name').val();
google.script.run
.withSuccessHandler(
function(narrative) {
$('#narrative-response').html(narrative);
})
.withUserObject(this)
.generateContentForSelected(projectName, templateName);
}
</script>
<body>
<div>
<br />
<br />
<form>
Project Name: <input type="text" name="project-name" id="project-name" onchange="google.script.run.updateProjectAndTemplateNames(this.parentNode)"><br />
Template Name: <input type="text" name="template-name" id="template-name" onchange="google.script.run.updateProjectAndTemplateNames(this.parentNode)"><br />
<button id="narrative-from-selection">Generate from Selection</button><br /><br />
Response:<br /><br />
<div id="narrative-response"></div>
</form>
</div>
</body>
</html>
Code.gs
Here is the overview of the relevant function that I'm using (the info used to hit the API is removed but I've tested that piece many times and it returns exactly what I expect it to send back).
function generateContentForSelected(projectName, templateName) {
// go do some API magic here
var narrative = "This is a test string.";
return narrative;
}
Through a ton of trial and error, I figured out what was causing the issue, though I'm still unsure why it's causing the new tab to open. Apparently, something about the way app script makes an asynchronous call using a form is a little quirky. I stripped the <form> and </form> tags out of the Sidebar.html file and everything works as expected.
If there's a better method to correct this, or if I've gone about this all wrong from the start, I'd be interested to know how to structure this more effectively. But, I did get it working at least.
Related
We have created sidebar for Google sheets and added few buttons to format data easily. But the problem is, these buttons work for the one who created the sidebar. For all other users they do nothing and functions don't get called. Functions themselves are fully tested and they work well. Seems like other users just can't call them on button click.
This is the code for sidebar (The functions are located in separate final.gs file):
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button id="clean" >Clean Up Data</button><br>
<button id="categories" >Style Categories</button><br>
<button id="test" >Run All </button><br>
<button id="delete" >Delete All </button><br>
<script>
document.getElementById("test").addEventListener("click", function(){
google.script.run.call_all_funcions();
});
document.getElementById("clean").addEventListener("click", function(){
google.script.run.cleanUpData();
});
document.getElementById("categories").addEventListener("click", function(){
google.script.run.style_categories_WithBorders();
});
document.getElementById("delete").addEventListener("click", function(){
google.script.run.clearSheet();
});
</script>
</body>
</html>
What are we doing wrong? Or maybe there are some kind of permissions?
I tried to debug and returned error message. Turned out it was permission issues. The solution was to simply sign out of all Google accounts and then sign in with only the one that has permissions to edit the file. Now everything works.
I'm just starting to use Google Apps Script's HTML service to create a UI. Starting out very basic and Google's documentation seems to be very incomplete (let me know if I missed something). I followed this example: https://developers.google.com/apps-script/guides/html/reference/run#withUserObject(Object) and got it to work, but I don't understand where the "this" came from (in the HTML code) and how the order of operations works there.
In order to wrap my mind around this, I'm trying to make something where I can put in text, push a button, and it will display the same text in all-caps. Here's what I've got so far:
Google Script:
function doGet() {
return HtmlService.createHtmlOutputFromFile('index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
HTML:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function capitalize(input){
return input.toUpperCase();
}
</script>
</head>
<body>
Put some text here: <input type="text" name="words"><br>
<input name="button" type="button" value="CAPITALIZE" onclick="google.script.run
.withSuccessHandler(capitalize)
.withUserObject(words)"><br><br>
Here is your text:
</body>
</html>
Any help is GREATLY appreciated!
The documentation for .gs is actually really good. Don't go into any language's docs expecting "full explanations" for every use case though.
google.script.run is only needed when you want to pass data to a server-side .gs function ( as documented at the top of the page you linked to ).
What you're asking for seems to be all client-side manipulation though, with no need to pass data to a .gs function.
try these adjustments:
// get value of a text box and set it into html of a <span> element
function capitalize(){
document.getElementById('userInput').innerHTML =
document.getElementById("words").value.toUpperCase();
}
onclick="capitalize()"><br><br>
Here is your text:<span id="userInput"></span>
I am experiencing a confusing error (for me it is confusing since I am new to this sort of thing, and I cannot find any good tutorials on it either) when I try to integrate a Dropbox saver into my webpage. The webpage is built using MVC4. The problem I am experiencing is that when I click on the "Save to Dropbox" button, I get the following error in dropins.js:
"Failed to open a popup window. Dropbox.choose and Dropbox.save should only be called from within a user-triggered event handler such as a tap or click event."
What does it mean? How must I rewrite my code to make this work? I've even tried making a button that calls Dropbox.save(), but the same error pops up.
So, the code:
// Button to open the saver dialog.
<button onclick="openSaveDialog();">Save</button>
// Javascript function.
function openSaveDialog() {
window.open('#Url.Action("SaveDialog")', '_blank');
}
// Controller function called by the above Javascript function.
public ActionResult SaveDialog()
{
return View();
}
// Here is the code for the save dialog. Note that the key to the Dropbox javascript link has been omitted for my safety ;)
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Save</title>
<script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="<key omitted for safety>"></script>
</head>
<body>
<div id="save">
</div>
</body>
</html>
Any advice is warmly welcome... been scratching my head at this for a good two days now, trying to find any tutorials at all.
Following up from my solved [previous issue][1], I'm having trouble building a simple HTML Web resource containing some basic javascript, page is rendered correctly but script doesn't seem to work properly.
My HTML resource is very basic:
<html>
<head>
<script src="ClientGlobalContext.js.aspx" />
<script type="text/javascript" src="new_jquery_1.7.2.min" />
<script type="text/javascript">
function buttonClick() { alert('Yo !'); }
</script>
</head>
<body>
<input type="button" value="Test" onclick="javascript: buttonClick();" />
</body>
</html>
Although the page shows up fine, clicking the button yields The value of the property is null or undefined not a function object error like the functions wasn't there, but I checked via F12 console that the code is rendered correctly.
I also tried invoking the web resource via the direct url, in the form of
http://mycrmserver/myorg/WebResources/new_myResource
But (as I expected) the behavior of the page was the same.
I checked Google, I surfed a couple of other SO questions and MSDN and all state this is the right way to do it, what's wrong with my code ?
Other (not sure if useful) details:
If the F12 tool is open the error comes up as a SCRIPT5007 javascript runtime error in the console. If it's not, I get the usual script error notify popup if I browse to the webresource direct url, or nothing happens at all if I try to open the resource inside the CRM.
The CRM environment is updated to Rollup 3 (updating it is not an option unfortunately)
I'm using IE 9 (Remember: Dynamics CRM can't be used in non-IE browsers yet)
UPDATE
Shorthand tags confuse the CRM.
Basically this syntax sometimes gets messed up:
<script src="ClientGlobalContext.js.aspx" />
But this works perfectly:
<script src="ClientGlobalContext.js.aspx"></script>
Root cause is a missing script tag, despite the code you posted being correct.
CRM does some messing about with the HTML you post into the script editor window. What is rendered in the browser is this (note that the ClientGlobalContext.js.aspx tag is not closed in the same way as your pasted code):
<HTML><HEAD>
<SCRIPT src="ClientGlobalContext.js.aspx">
<script type="text/javascript" src="new_jquery_1.7.2.min" />
<script type="text/javascript">
function buttonClick() { alert('Yo !'); }
</SCRIPT>
<META charset=utf-8></HEAD>
<META charset=utf-8></HEAD>
<BODY><INPUT onclick=javascript:buttonClick(); value=Test type=button></BODY></HTML>
Resolution:
Add full "close" tags to each opening script tag (rather than using "/>").
I'm trying to use http://www.asual.com/jquery/address/ for history management, this works absolutely fine when we work on "a" tags, but now I've search module which trigger when I click on a search button and I'm trying to include the search text in the address(and also the page number), so that when the user uses the backs button he/she can also see what search they have done previously. Any help will be greatly appreciated.
Edited:
Reference - http://www.asual.com/jquery/address/
I'm building AJAX application, so all the modules are loaded using AJAX and to keep a track of the history I'm using: http://www.asual.com/jquery/address/, till now all the links are "a" href's which I'm coding as Public
Now, I'm working on the search page which has a search TextBox and a searchButton, so when the user enters in the text box and clicks on searchButton, the url has to be adjusted accordingly so when the user directly enters (or comes to that URL using BACK button), the search results should be displayed, this is similar to the "SEARCH MAIL" button in gmail, please note how the url is changing, here I'm also trying to achieve the same thing.
Hope it is clear, thanks.
Regards
I bealive you're looking for something like in this example.
Simplified example:
<html>
<head>
<title>jQuery Address Form</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="jquery.address.js"></script>
<script type="text/javascript">
$.address.init(function(event) {
$('form').address();
})
.change(function(e) {
// for anything that isn't homepage
if (e.value != '/') {
// load results for url in e.value, for example:
$("#results").load(e.value);
}
})
</script>
</head>
<body>
<div class="page">
<h1>jQuery Address Form</h1>
<form action="find.php" method="get">
<label for="input">Query</label><br>
<input id="input" name="input" type="text" value="" size="60"/>
<input id="submit" name="submit" type="submit" value="Submit"/>
</form>
<div id="results">
</div>
</div>
</body>
</html>
When you submit the form, the url is changing. The change event is then handled by my code. e.value is a url in this example, so when the url is changing we're trying to load search results into the #results div.
The same change handler is used when user navigates using the "back" button in his/her browser.
There exists whole jQuery plugin for that, called jQuery BBQ: Back Button & Query Library. Try out demo, and find if that is what you need.