Why is object key pair with null value not passed from server to client anymore? - google-apps-script

I have a Google application script web application where I use google.script.run.withSuccessHandler. Server side function returns an object where all the values are null. MaterializeCSS autocomplete requires nulls
My customer today reported that the GAS web stopped working. It was 10000000% working before. I found out that the reason is a null as a value.
Working sample applicatin is here
https://script.google.com/macros/s/AKfycbzbg4YLndZ0zORBzgDc3ETLUdJeToUS1nKjORUa5fNxQt9syXmLlX1gDHzgS4w8iCBM9A/exec
https://script.google.com/d/1Uba73PIetb9fmrO44nwsmAd_epZTHy4lwz5bG3bURK3jqpd161JT0pf5/edit?usp=sharing
HTML code
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Test
<script type="text/javascript">
console.log("test")
document.addEventListener("DOMContentLoaded", function(event) {
google.script.run.withSuccessHandler(afterDataReceived)
.returnObject()
});
function afterDataReceived(receivedData){
console.log(receivedData)
}
</script>
</body>
</html>
GS code
function doGet(e) {
var htmlTemplate = HtmlService.createTemplateFromFile("index").evaluate()
return htmlTemplate
}
function returnObject(){
var object = {}
object.a = "123"
object.b = null
object.c = 123
console.log(object)
return object
}
Is someone experiencing the same error? How to fix this?

Issue:
If null is a value for a key in a object, the key-value pair is lost when the object is passed from server to client, though null is a legal parameter.I can confirm the issue.
Solution:
The issue is reported here. Add a star to the issue, if anyone else has the same issue.
As a typical workaround for illegal parameters, Use JSON.stringify() on the server side, pass the string to the client and JSON.parse() it client side to get nulls inside a object.
Server:
function returnObject(){
return JSON.stringify({a:1,b:null,c:3});
}
Client:
document.addEventListener("DOMContentLoaded",
function(event) {
google.script.run
.withSuccessHandler(afterDataReceived)
.returnObject()
});
function afterDataReceived(receivedData){
console.log(JSON.parse(receivedData));
}

Related

Why would this function generate an http: 500 error on one of my files?

I started getting this error in a lot more complicated script and after a while I tried this extremely simple case. When I click the button I get the error: NetworkError: Connection failure due to HTTP 500
and of course I get the same thing in the console. I've moved it to another file and the error goes away.
gs:
function runTwo() {
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutputFromFile('test'),'Title');
}
function getMessage() {
return 'Hello World';
}
html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div id='msg1'></div>
<input type="button" value="Click Me" onClick="iveBeenClick();" />
<script>
function iveBeenClick() {
google.script.run
.withFailureHandler(msg=>{document.getElementById("msg1").innerHTML=msg;})
.withSuccessHandler(msg=>{document.getElementById("msg1").innerHTML=msg;})
.getMessage();
}
</script>
</body>
</html>
Just in case it matters, this file has a webapp deployed that works with a Gmail Addon to delete unwanted emails. And here's that code:
function doGet(e) {
Logger.log('query params: ' + Utilities.jsonStringify(e));
if(e.queryString !=='')
{
switch(e.parameter.mode){
case 'dable':
deleteAllBlackListedEmails2();
return ContentService.createTextOutput("delete black list Done!!!!");
break;
case 'append':
const length=appendToBlackList({deletes:e.parameter.bls});
return ContentService.createTextOutput(length);
break;
case 'length':
return ContentService.createTextOutput(getBlackListLength());
break;
default:
return ContentService.createTextOutput("<h1>Unknown Command: " + e.parameter.mode);
}
}else{
return ContentService.createTextOutput("No Query String");
}
}
I'd like to know what the problem is. But I don't know where to go from here. I could certainly live without knowing and it doesn't seem to be affecting the performance of the other functions but it does impact my ability to built interactive tools for analyzing my data because I can't use google.script.run on any of my dialogs. Anyway I thought I'd ask and see if anyone else might be able to get it to fail.
New Information
Problem went away when I removed a library that I just installed. What should I looked for in that library?
The Fix
Because I was unfamiliar with the new dialog I chose to use the head deployment and I really wanted version 31. I don't know why this causes such an error but the script seems to be back to normal now. I was lucky this time.
I just wanted to share with everyone a simple way to avoid the HTTP 500 problem described above. It's fairly simple to reproduce and looking back upon it I can see now that it occurred because I was unfamiliar with the new editor and I made the simple error of not selecting a version. Instead I left it the head deployments which is a problem.
This is my minimum complete verifiable example.
I created a simple library with only one function and I called it the HTTP500Library
The Function:
function selectColumnsSkipHeader() {
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sht=ss.getActiveSheet();
var rng=sht.getActiveRange();
var rngA= sht.getActiveRange().getA1Notation().split(':');
var ul=rngA[0].replace(/\d+/,'');
if(rng.getNumColumns()>1) {
var lr=rngA[1].replace(/\d+/,'');
}
else {
lr=ul;
}
var rngs=ul + rng.getRow() + ':' + lr;
var outrng=sht.getRange(rngs);
outrng.activate();
}
Then I deployed and actually due to a couple of stupid mistakes I have a couple of deployments
Then I created another spreadsheet called the HTTP500 Problem and I put this code into it:
Code.gs:
function onOpen() {
SpreadsheetApp.getUi().createMenu('My Tools')
.addItem('Simple Dialog', 'runTwo')
.addToUi();
}
function runTwo() {
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutputFromFile('problem'),'Title');
}
function getMessage() {
return 'Hello World';
}
HTML:
function iveBeenClick() {
google.script.run
.withFailureHandler(msg=>{document.getElementById("msg1").innerHTML=msg;})
.withSuccessHandler(msg=>{document.getElementById("msg1").innerHTML=msg;})
.getMessage();
}
</html><!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div id='msg1'></div>
<input type="button" value="Click Me" onClick="iveBeenClick();" />
<script>
function iveBeenClick() {
google.script.run
.withFailureHandler(msg=>{document.getElementById("msg1").innerHTML=msg;})
.withSuccessHandler(msg=>{document.getElementById("msg1").innerHTML=msg;})
.getMessage();
}
</script>
</body>
</html>
After setting up the problem I tested the dialog that I just created and it worked fine with no problems.
Then I added the library that I just created but because I was unfamiliar with the new editor I mistakenly chose the head deployment. In other words I didn't select a version.
I ran the dialog again and this time I recieved the Network Connection problem with the HTTP 500 error.
The next step should have been to realize that I didn't select the correct version and return to the dialog and do so and that would have fixed the problem.
So I guess the Network connection that cause the problem was the connection to the library. So don't forget to pick the appropriate deploy of your libraries when you install them.
Thank for all the help

HTML5/websockets/javascript based real-time logfile viewer?

Im looking for the equivalent of "tail -f" that runs in a browser using html5 or javascript.
A solution would need a client side code written in HTML5/websockets/javascript and a back-end server side application. Im looking for one in c# but i'm willing to rewrite it from php or python.
This is the only thing that i've seen that comes close is
http://commavee.com/2007/04/13/ajax-logfile-tailer-viewer/
However, modern browsers have WebSockets which makes the problem much simpler.
http://www.websocket.org/echo.html
Ideally, I would like to have some of the capabilities of BareTail
http://www.baremetalsoft.com/baretail/
Such as Color Coding of lines, sorting and multi-file tabbing.
I have located a similar posting where someone is looking for windows based log file programs
https://stackoverflow.com/questions/113121/best-tail-log-file-visualization-freeware-tool
Anyone have any suggestions?
It is not exactly like tail but the live logs feature of https://log4sure.com does allow you to monitor your client side logs realtime. You would have to setup and do the logs appropriately as you would do for tailing, but you can see all the logs with extra information about your client, example browser, os, country etc. You can also create your own custom logs to log stuff. Checkout the demo on the site to get a better idea.
The setup code is really easy, and the best part is, its free.
// set up
var _logServer;
(function() {
var ls = document.createElement('script');
ls.type = 'text/javascript';
ls.async = true;
ls.src = 'https://log4sure.com/ScriptsExt/log4sure-0.1.min.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ls, s);
ls.onload = function() {
// use your token here.
_logServer = new LogServer("use-your-token-here");
};
})();
// example for logging text
_logServer.logText("your log message goes here.")
// example for logging error
divide = function(numerator, divisor) {
try {
if (parseFloat(value) && parseFloat(divisor)) {
throw new TypeError("Invalid input", "myfile.js", 12, {
value: value,
divisor: divisor
});
} else {
if (divisor == 0) {
throw new RangeError("Divide by 0", "myfile.js", 15, {
value: value,
divisor: divisor
});
}
}
} catch (e) {
_logServer.logError(e.name, e.message, e.stack);
}
}
// another use of logError in window.onerror
// must be careful with window.onerror as you might be overwriting some one else's window.onerror functionality
// also someone else can overwrite window.onerror.
window.onerror = function(msg, url, line, column, err) {
// may want to check if url belongs to your javascript file
var data = {
url: url,
line: line,
column: column,
}
_logServer.logError(err.name, err.message, err.stack, data);
};
//example for custom logs
var foo = "some variable value";
var bar = "another variable value";
var flag = "false";
var temp = "yet another variable value";
_logServer.log(foo, bar, flag, temp);
While I wish it had better JSON object prettification for live tailing and historical logs, the following JS client works and supports your server-side requirement also:
https://github.com/logentries/le_js/wiki/API
<html lang="en">
<head>
<title>Your page</title>
<script src="/js/le.min.js"></script>
<script>
// Set up le.js
LE.init('YOUR-LOG-TOKEN');
</script>
</head>
.....
<script>
// log something
LE.log("Hello, logger!");
</script>
Personally to get the above code to work however, I've had to add the following line of code just above LE.init('YOUR-LOG-TOKEN'):
window.LEENDPOINT = 'js.logentries.com/v1'
.. Alternatively, Loggly may be a fit as well: https://www.loggly.com/docs/javascript/

JSON and passing a URL value as a parameter - Chrome Extension

Ok, this is my final tango with this. Below I've listed the code. I'm able to get the value of the url and display it on screen for the current (active tab) in Google Chrome. Now all I have to do is pass that value as a parameter in the URL via JSON. My processing file resides on a our remote server - in php. Everything I've done with respect to this has worked to perfection. However, any attempts to pass the current url or any url as one of the parameters - e.g. ?format=json&url=http://something.com&callback=? - results in nothing. I'm not sure if what I'm doing is wrong or if it is even possible. The important thing to note is that all we are looking to do is pass the url to a remote server for storage, processing etc and send back results. I have everything working but I just can't seem to get the url to pass as a parameter.
<html>
<head>
<title>API JSON Test</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js"></script>
<script>
window.addEventListener("load", windowLoaded, false);
function windowLoaded() {
chrome.tabs.getSelected(null, function(tab) {
document.getElementById('currentLink').innerHTML = tab.url;
});
}
</script>
<script type="text/javascript">
$(document).ready(function(){
var timeService =
"http://api.ulore.com/api2.php?key=abce&url="+tab.url+"&format=json&callback=?";
$.getJSON(timeService, function(data) {
$('#showdata').html("<p>url_results="+data.post.url+"</p>");
});
});
</script>
<div id="showdata"></div>
</head>
<body>
</body>
</html>
Again, all the JSON works fine when I'm testing other code. Even if I put in a NON-URL value as a parameter for url=..... it throws the appropriate error. However, it will not accept a URL for some reason.
Any feedback will be greatly appreciated.
Thanks,
Ethan-Anthony
Try encoding and decoding the url.
http://www.w3schools.com/tags/ref_urlencode.asp
http://php.net/manual/en/function.rawurlencode.php
http://phpjs.org/functions/rawurlencode:501

Not able to parse JSON file in JavaScript

I am using JavaScript to Parse the JSON file. But I am not able understand the error I am getting. Could anybody please help me on this topic.
**My Code:
Html file:
<title>JSON Parser</title>
<script type="text/javascript">
function webGLStart() {
var request = new XMLHttpRequest();
request.open("GET","test.json");
var my_JSON_object = JSON.parse(request.responseText);
alert (my_JSON_object.result[0]);
}
</script>
</head>
<body onload="webGLStart();">
</body>
</html>
test.json File:
{"result": [0,1,2,3,4] }
alert in above code does not show anything on the webpage.
It's straight forward with jQuery:
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$.getJSON('test.json', function(data) {
$.each(data, function(key, val) {
console.log("key=" + key + " " + "val=" + val);
});
});
For more sample code look here: http://api.jquery.com/jQuery.getJSON/
Your code for making the Ajax request is not correct.
First, var request = new XMLHttpRequest(); will not work incase of IE 5, 6; i.e. you need to make cross-browser object of XMLHttp
Second, request.open("GET","test.json"); does not indicate this request to be asynchronous... i.e. you are missing the third boolean parameter (true / false)
Thirdly, you are not sending the request to the web server using:
request.send(null);
Try following link for Ajax:
http://www.w3schools.com/ajax/ajax_xmlhttprequest_send.asp
Try this link for Parsing JSON using Javascript:
http://json.org/js.html
Hope this helps.
Ajax is asynchronous. You are trying to read the response before it has arrived from the server. Oh, worse than that. You are opening the request but never actually sending it.
You need to use an event handler onreadystate change to run the code once the response has arrived, and you need to send the request to the server before you can get a response. There is a decent guide to using XHR here.

localStorage doesn't retrieve values after page refresh

I'm trying to test out html5 localStorage feature. For some reason, whenever I try to retrieve a value from storage after refreshing the page, I only get null values returned. (If I try retrieving the values in the same function that I set them in, then I can properly retrieve them).
One thing: the html/javascript that I'm loading is being requested from the local disk (for example, I'm using the string: "file:///C:/testLocalStore.html" to browse to the file, instead of requesting it from a web server. Would this cause the localStore problems that I'm seeing?
(I'd like to post the full code example, but I'm having some problems with the formatting. I'll post it shortly).
<html> <head> <title>test local storage</title>
<base href="http://docs.jquery.com" />
<script src="http://code.jquery.com/jquery-1.3.js"></script>
<script type="text/javascript">
function savestuff()
{
var existingData = localStorage.getItem("existingData");
if( existingData === undefined || existingData === null )
{
// first time saving a map.
existingData = $("#mapName").val();
}
else
{
existingData = existingData + "," + $("#mapName").val();
}
localStorage.setItem("existingData", existingData);
// test is non-null here, it was properly retrieved.
var test = localStorage.getItem("existingData");
}
$(document).ready( function init()
{
// existing data is always null.
var existingData = localStorage.getItem("existingData");
if( existingData !== null )
{
var existingDataListHtml = existingData.split(",");
existingDataListHtml = $.each(existingData, function(data) {
return "<li>" + data + "<\/li>";
});
$("#existingData").html("<ul>" + existingDataListHtml + "<\/ul>");
}
} );
</script>
</head> <body>
<form id="loadFromUser" onsubmit="savestuff();">
<input id="mapName" type="text">
<input type="submit" value="save">
</form>
<div id="existingData"> </div>
</body> </html>
Yes, loading the file locally means that it doesn't have an origin. Since localStorage is uses the same-origin policy to determine access to stored data, it is undefined what happens when you use it with local files, and likely that it won't be persisted.
You will need to host your file on a web server in order to have a proper origin; you can just run Apache or any other server locally and access it via localhost.