At the Google Apps Script project, the values can be transferred from HTML to Google Apps Script using google.script.run
with Javascript. In this case, unfortunately, the values of all types cannot be transferred. In the official document, it says as follows. Ref
Most types are legal, but not Date, Function, or DOM element besides form; see description
Legal parameters are JavaScript primitives like a Number, Boolean, String, or null, as well as JavaScript objects and arrays that are composed of primitives, objects, and arrays. A form element within the page is also legal as a parameter, but it must be the function’s only parameter. Requests fail if you attempt to pass a Date, Function, DOM element besides a form, or other prohibited type, including prohibited types inside objects or arrays. Objects that create circular references will also fail, and undefined fields within arrays become null. Note that an object passed to the server becomes a copy of the original. If a server function receives an object and changes its properties, the properties on the client are not affected.
From this document, it can know about the values (number, boolean, string, array, and object including them) for often can be used. But, there are the values of more types in Javascript. It is considered that when the values that can be used for this situation are clearly known, it will be useful for a lot of developers. This report introduces the values that can be used for transferring between HTML and Google Apps Script with google.script.run.
1. From HTML to Google Apps Script
This section introduces the values that can be transferred from HTML to Google Apps Script with google.script.run. The sample script can be seen in the “Appendix” section. As a result, the following table could be obtained.
Passed values
Input value | Input type | Output value | Output type | Result (Pass or Fail) |
---|---|---|---|---|
123 |
Number | 123 |
Number | Pass |
"sample" |
String | "sample" |
String | Pass |
true |
Boolean | true |
Boolean | Pass |
new Array(1).fill("sample") |
Array | ["sample"] |
Array | Pass |
new Array(1).fill(new Array(1).fill("sample")) |
Array | [["sample"]] |
Array | Pass |
{ key: "value" } |
Object | { "key": "value" } |
Object | Pass |
document.getElementById("form") |
Form object including input tag | { "sample text": "sample value" } |
Object | Pass |
null |
Null | null |
Null | Pass |
Failed values
Input value | Input type | Output value | Output type | Result (Pass or Fail) |
---|---|---|---|---|
new Number(123) |
Number | Fail | ||
new String("sample") |
String | Fail | ||
new RegExp("^.*$") |
RegExp | Fail | ||
function () { return "ok" } |
Function | Fail | ||
document.getElementById("text") |
Input tag object | Fail | ||
new Date() |
Date | Fail | ||
[0, 1, 2, new Date(), 4, 5] |
Array including date | Fail | ||
new Map([["a", "b"]]) |
Map | Fail | ||
new Set(["a", "b"]) |
Set | Fail | ||
new Promise(res => res("ok")) |
Promise | Fail | ||
new Blob(["sample text"], { type: 'text/plain' }) |
Blob | Fail | ||
new Blob(["sample text"], { type: 'text/plain' }).arrayBuffer() |
Array buffer | Fail | ||
new Int8Array(buffer) |
Int8Array | Fail | ||
new Uint8Array(buffer) |
Uint8Array | Fail | ||
new Blob(["sample text"], { type: 'text/plain' }).stream() |
Stream object | Fail | ||
undefined |
undefined | null |
Null | Fail |
- In the case of
[0, 1, 2, new Date(), 4, 5]
, an error likeFailed due to illegal value in property: 3
occurred. By this, it is found that an error occurs at the index of 3.
2. From Google Apps Script to HTML
This section introduces the values that can be transferred from Google Apps Script to HTML with google.script.run. The sample script can be seen in the “Appendix” section. As a result, the following table could be obtained.
In this section, the input value and output value are the opposition from the above section. Please be careful about this.
Passed values
Input value | Input type | Output value | Output type | Result (Pass or Fail) |
---|---|---|---|---|
123 |
Number | 123 |
Number | Pass |
"sample" |
String | "sample" |
String | Pass |
true |
Boolean | true |
Boolean | Pass |
new Array(1).fill("sample") |
Array | ["sample"] |
Array | Pass |
new Array(1).fill(new Array(1).fill("sample")) |
Array | [["sample"]] |
Array | Pass |
{ key: "value" } |
Object | {"key":"value"} |
Object | Pass |
Utilities.newBlob("sample text", 'text/plain').getBytes() |
Bytes | [115,97,109,112,108,101,32,116,101,120,116] |
Array | Pass |
new Int8Array(bytes) |
Int8Array | {"0":115,"1":97,"2":109,"3":112,"4":108,"5":101,"6":32,"7":116,"8":101,"9":120,"10":116} |
Object | Pass |
null |
Null | null | Null | Pass |
Failed values
Input value | Input type | Output value | Output type | Result (Pass or Fail) |
---|---|---|---|---|
new Number(123) |
Number | {} |
Object | Fail |
new String("sample") |
String | {"0":"s","1":"a","2":"m","3":"p","4":"l","5":"e"} |
Object | Fail |
new RegExp("^.*$") |
RegExp | {} |
Object | Fail |
function () { return "ok" } |
Function | "function () { return \"ok\" }" |
String | Fail |
new Date() |
Date | No value | Fail | |
[0, 1, 2, new Date(), 4, 5] |
Array including date | No value | Fail | |
new Map([["a", "b"]]) |
Map | {} |
Object | Fail |
new Set(["a", "b"]) |
Set | {} |
Object | Fail |
new Promise(res => res("ok")) |
Promise | "ok" |
String | Fail |
Utilities.newBlob("sample text", 'text/plain') |
Blob | {"setName":"function () { [native code] }","setBytes":"function () { [native code] }",,,} |
Object | Fail |
new Uint8Array(bytes).buffer |
Array buffer | {} |
Object | Fail |
new Uint8Array(bytes) |
Uint8Array | "サーバー エラーが発生しました。しばらくしてからもう一度試してください。" |
Fail | |
undefined |
undefined | null | Null | Fail |
SpreadsheetApp.getActiveSpreadsheet() |
Class Spreadsheet object | No value | Fail |
Summary
This report investigated the values to transfer between Javascript and Google Apps Script with google.script.run
. From this report, the following result was obtained.
-
In the case that the values are transferred from HTML to Google Apps Script, the following values can be transferred.
- Number
- String
- Boolean
- Array
- JSON object constructed with numbers, values, and boolean
- Form object
- Null
-
In the case that the values are transferred from Google Apps Script to HTML, the following values can be transferred.
- Number
- String
- Boolean
- Array
- JSON object constructed with numbers, values, and boolean
- Byte array
- Int8Array
- Null
-
As an important point, when the failed value is included in an array and JSON object, an error occurs. Please be careful about this.
-
When you want to transfer the failed values, it is required to convert them to the passed values like string and byte array. By this, you can transfer between HTML and Google Apps Script with
google.script.run
.
When you develop a script for transferring values between HTML and Google Apps Script with google.script.run, when the values cannot be correctly transferred, if this report is useful, I’m glad.
Appendix
Script of “From HTML to Google Apps Script”
Google Apps Script
const doGet = (_) => HtmlService.createHtmlOutputFromFile("index");
const sample1 = (e) => {
const obj = ["null", "undefined", "", "0"];
if (e) {
const type = typeof e;
return { response: e, type };
}
return { response: obj[[null, undefined, "", 0].findIndex((f) => f === e)] };
};
HTML & Javascript
<script src="https://cdn.jsdelivr.net/gh/tanaikech/syncGoogleScriptRun@master/syncGoogleScriptRun.min.js"></script>
<form id="form">
<input type="text" value="sample value" name="sample text" id="text" />
</form>
<input type="button" value="run" onclick="run()" />
<script>
async function run() {
const blob = new Blob(["sample text"], { type: "text/plain" });
const buffer = await blob.arrayBuffer();
const obj = {
number1: 123,
number2: new Number(123),
string1: "sample",
string2: new String("sample"),
bool: true,
regex: new RegExp("^.*$"),
array1dObject: new Array(1).fill("sample"),
array2dObject: new Array(1).fill(new Array(1).fill("sample")),
jsonObject: { key: "value" },
functionObject: function () {
return "ok";
},
formObject: document.getElementById("form"),
inputTagObject: document.getElementById("text"),
date1Object: new Date(),
date2Object: [0, 1, 2, new Date(), 4, 5],
mapObject: new Map([["a", "b"]]),
setObject: new Set(["a", "b"]),
promiseObject: new Promise((res) => res("ok")),
blobObject: blob,
bufferObject: buffer,
int8ArrayObject: new Int8Array(buffer.buffer),
uint8ArrayObject: new Uint8Array(buffer.buffer),
streamObject: await blob.stream(),
nullValue: null,
undefinedValue: undefined,
};
const ret = {};
const err = [];
const noResponse = [];
for (let i in obj) {
const r = await syncGoogleScriptRun({
gasFunction: "sample1",
arguments: obj[i],
}).catch((e) => (err[i] = { error: e.message }));
if (r) {
ret[i] = r;
} else {
noResponse.push(i);
}
}
const keys = Object.keys(obj);
const res = keys.reduce((o, k) => ((o[k] = err[k] || ret[k]), o), {});
console.log(res);
console.log(err);
console.log(noResponse);
}
</script>
Result
console.log(res)
{
"number1": { "type": "number", "response": 123 },
"number2": { "error": "Failed due to illegal value in property: 0" },
"string1": { "type": "string", "response": "sample" },
"string2": { "error": "Failed due to illegal value in property: 0" },
"bool": { "type": "boolean", "response": true },
"regex": { "error": "Failed due to illegal value in property: 0" },
"array1dObject": { "type": "object", "response": ["sample"] },
"array2dObject": { "type": "object", "response": [["sample"]] },
"jsonObject": { "type": "object", "response": { "key": "value" } },
"functionObject": { "error": "Failed due to illegal value in property: 0" },
"formObject": {
"type": "object",
"response": { "sample text": "sample value" }
},
"inputTagObject": { "error": "Failed due to illegal value in property: 0" },
"date1Object": { "error": "Failed due to illegal value in property: 0" },
"date2Object": { "error": "Failed due to illegal value in property: 3" },
"mapObject": { "error": "Failed due to illegal value in property: 0" },
"setObject": { "error": "Failed due to illegal value in property: 0" },
"promiseObject": { "error": "Failed due to illegal value in property: 0" },
"blobObject": { "error": "Failed due to illegal value in property: 0" },
"bufferObject": { "error": "Failed due to illegal value in property: 0" },
"int8ArrayObject": { "error": "Failed due to illegal value in property: 0" },
"uint8ArrayObject": { "error": "Failed due to illegal value in property: 0" },
"streamObject": { "error": "Failed due to illegal value in property: 0" },
"nullValue": { "response": "null" },
"undefinedValue": { "response": "null" }
}
console.log(err)
[]
console.log(noResponse)
[]
Script of “From Google Apps Script to HTML”
Google Apps Script
const doGet = (_) => HtmlService.createHtmlOutputFromFile("index");
function sample2(e) {
const blob = Utilities.newBlob("sample text", "text/plain");
const bytes = blob.getBytes();
const buffer = new Uint8Array(bytes).buffer;
const obj = {
number1: 123,
number2: new Number(123),
string1: "sample",
string2: new String("sample"),
bool: true,
regex: new RegExp("^.*$"),
array1dObject: new Array(1).fill("sample"),
array2dObject: new Array(1).fill(new Array(1).fill("sample")),
jsonObject: { key: "value" },
functionObject: function () {
return "ok";
},
// formObject: document.getElementById("form"),
// inputTagObject: document.getElementById("text"),
date1Object: new Date(),
date2Object: [0, 1, 2, new Date(), 4, 5],
mapObject: new Map([["a", "b"]]),
setObject: new Set(["a", "b"]),
promiseObject: new Promise((res) => res("ok")),
blobObject: blob,
bytesObject: bytes,
bufferObject: buffer,
int8ArrayObject: new Int8Array(bytes),
uint8ArrayObject: new Uint8Array(bytes),
// streamObject: await blob.stream(),
nullValue: null,
undefinedValue: undefined,
googleAppsScriptClassObject: SpreadsheetApp.getActiveSpreadsheet(),
};
return obj[e];
}
HTML & Javascript
<script src="https://cdn.jsdelivr.net/gh/tanaikech/syncGoogleScriptRun@master/syncGoogleScriptRun.min.js"></script>
<input type="button" value="run" onclick="run()" />
<script>
async function run() {
const keys = [
"number1",
"number2",
"string1",
"string2",
"bool",
"regex",
"array1dObject",
"array2dObject",
"jsonObject",
"functionObject",
"date1Object",
"date2Object",
"mapObject",
"setObject",
"promiseObject",
"blobObject",
"bytesObject",
"bufferObject",
"int8ArrayObject",
"uint8ArrayObject",
"nullValue",
"undefinedValue",
"googleAppsScriptClassObject",
];
const ret = {};
const err = [];
const noResponse = [];
for (let i of keys) {
const r = await syncGoogleScriptRun({
gasFunction: "sample2",
arguments: i,
}).catch((e) => (err[i] = { error: e.message }));
if (r) {
const type = typeof r;
ret[i] = { response: r, type };
} else {
noResponse.push(i);
}
}
const res = keys.reduce((o, k) => ((o[k] = err[k] || ret[k]), o), {});
console.log(res);
console.log(err);
console.log(noResponse);
}
</script>
Result
console.log(res)
{
"number1": { "response": 123, "type": "number" },
"number2": { "response": {}, "type": "object" },
"string1": { "response": "sample", "type": "string" },
"string2": {
"response": { "0": "s", "1": "a", "2": "m", "3": "p", "4": "l", "5": "e" },
"type": "object"
},
"bool": { "response": true, "type": "boolean" },
"regex": { "response": {}, "type": "object" },
"array1dObject": { "response": ["sample"], "type": "object" },
"array2dObject": { "response": [["sample"]], "type": "object" },
"jsonObject": { "response": { "key": "value" }, "type": "object" },
"functionObject": {
"response": "function () { return \"ok\" }",
"type": "string"
},
"mapObject": { "response": {}, "type": "object" },
"setObject": { "response": {}, "type": "object" },
"promiseObject": { "response": "ok", "type": "string" },
"blobObject": {
"response": {
"setName": "function () { [native code] }",
"setBytes": "function () { [native code] }",
"getName": "function () { [native code] }",
"getDataAsString": "function () { [native code] }",
"getAllBlobs": "function () { [native code] }",
"setDataFromString": "function () { [native code] }",
"getBytes": "function () { [native code] }",
"getAs": "function () { [native code] }",
"isGoogleType": "function () { [native code] }",
"getContentType": "function () { [native code] }",
"toString": "function () { [native code] }",
"setContentTypeFromExtension": "function () { [native code] }",
"setContentType": "function () { [native code] }",
"copyBlob": "function () { [native code] }"
},
"type": "object"
},
"bytesObject": {
"response": [115, 97, 109, 112, 108, 101, 32, 116, 101, 120, 116],
"type": "object"
},
"bufferObject": { "response": {}, "type": "object" },
"int8ArrayObject": {
"response": {
"0": 115,
"1": 97,
"2": 109,
"3": 112,
"4": 108,
"5": 101,
"6": 32,
"7": 116,
"8": 101,
"9": 120,
"10": 116
},
"type": "object"
},
"uint8ArrayObject": {
"error": "サーバー エラーが発生しました。しばらくしてからもう一度試してください。"
}
}
console.log(err)
[]
console.log(noResponse)
[
"date1Object",
"date2Object",
"nullValue",
"undefinedValue",
"googleAppsScriptClassObject"
]