Using JSON files in html - html

I'm have trouble to understand how to use the data saved in a JSON file and load it in a html page Everything locally:
say this the JSON file :
{
"level1":{
"level1_1":{
"example": "test",
"example2":"123123"
},
"level1_2":{
"example": "test",
"example2":"123123"
}
},
"level2":{
"level2_1":{
"example": "test",
"example2":"123123"
},
"level2_2":{
"example": "test",
"example2":"123123"
}
}
}
And I want to be able to call the data from it, in and HTML file for example :
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reading json</title>
<style>
</style>
</head>
<body>
<br>
file value :
<br>
<script>
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'config.json', true); // Replace 'my_data' with the path to your file
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
}
function init() {
loadJSON(function(response) {
// Parse JSON string into object
var actual_JSON = JSON.parse(response);
});
}
</script>
</body>
I've got the script from this tutorial and still do get it run.
So my aim just to see after ** first value** data from the JSON file.
any idea how u guys do it ?

Here is a more elaborate answer.
First, let's parse the JSON into an object.
var actual_JSON = JSON.parse(response);
Second, transform the JSON object into a readable string.
var json_string = JSON.stringify(actual_JSON, undefined, 2);
Then, use the querySelector() function to select a DOM element. Note that #output means I want to select an ID attribute named output.
var output = document.querySelector("#output");
Then, I am adding by the JSON string to the DOM with the DOM innerHTML property. It will be added right after "file value".
output.innerHTML += json_string;
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reading json</title>
<style>
</style>
</head>
<body>
<br>
<div id="output">file value : </div>
<br>
<script>
// Starts.
init();
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'config.json', true); // Replace 'my_data' with the path to your file
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
// init(xobj.responseText)
}
};
xobj.send(null);
}
function init() {
loadJSON(function(response) {
// Parse JSON string into object
var actual_JSON = JSON.parse(response);
// Transforms the JSON object into a readable string.
var json_string = JSON.stringify(actual_JSON, undefined, 2);
// Select <br> tag.
var output = document.querySelector("#output");
// Adds it to the DOM.
output.innerHTML += json_string;
});
}
</script>
</body>

You have to add some id attribute in html, then select based on that id and loop the json data and insert like this
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reading json</title>
<style>
</style>
</head>
<body>
<div id="json_result"></div>
<script>
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'config.json', true); // Replace 'my_data' with the path to your file
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
}
function init() {
loadJSON(function(response) {
// Parse JSON string into object
var actual_JSON = JSON.parse(response);
for (var key in actual_JSON) {
var innerkey = actual_JSON[key];
for (var inner in innerkey) {
document.getElementById('json_result').innerHTML += 'Example: '+innerkey[inner]['example']+'<br>';
document.getElementById('json_result').innerHTML += 'Example2: '+innerkey[inner]['example2']+'<br>';
}
}
});
}
init();
</script>
</body>

This stack overflow question will guide you well

Related

How can I use google.script.run properly?

I've been recently working on a project that sends values to a google spreadsheet and
the failure handler always gives me an alert, am I doing something wrong?
By the way, here's the code:
MainGsFile.gs:
var Server = SpreadsheetApp.openByUrl("Spreadsheet Url");
//I know that's not the Spreadsheet Url
var Pages = Server.getSheets();
function doGet()
{
return HtmlService.createHtmlOutputFromFile("MainHtmlFile");
}
function SetCellValue(PageNum, Row, Column, Value)
{
Page[PageNum].getRange(Row, Column).setValue(Value);
}
function GetCellValue(PageNum, Row, Column)
{
return Page[PageNum].getRange(Row, Column).getValue();
}
MainHtmlFile.html:
<!DOCTYPE html>
<!--HTML Code-->
<html>
<body>
<button onclick="Test()">It's going to work</button>
</body>
</html>
<!--CSS Code-->
<style>
//Styles go here
</style>
<!--JavaScript Code-->
<script>
function Test()
{
google.script.run.withSuccessHandler(OnSuccess).withFailureHandler(OnFailure).SetCellValue(1, 1, 1, "true");
}
function OnSuccess()
{
alert("Yes");
}
function OnFailure()
{
alert("No");
}
</script>
Yes,
You can't pass mutiples arguments. Trick is to use object :
var obj = {};
obj.value = 1;
obj.value2 = 2;
obj.value3 = 3;
obj.bool = true;
google.script.run.withSuccessHandler(OnSuccess).withFailureHandler(OnFailure).SetCellValue(obj);

Malformed html error thrown from html based object in appscript

I've hit a wall on an issue when I try to display the content.text object in apps script, it returns a malformed html error specifically regarding my fetch to a GET request of
https://www.cloudconnect.xxx...
I get everything I need, but the content.text bit which is throwing a malformed html error in apps script. I'd like to use the html and return the documents as is with proper formatting and believe that I can properly parse this html to apps script using htmloutput as it needs to be sanitized, but I believe it's what's throwing the malformed html object. How can I proceed without escaping html characters? How can I properly parse this? Has anyone been successful at this by any chance?
Example of content.text:
<body>
<!-- [DocumentBodyStart:a63392fa-f859-4513-867e-1f3d2714b006] -->
<div class=\"jive-rendered-content\">
<p>Hi,team!</p>
<p style=\"min-height: 8pt; padding: 0px;\"> </p>
<p>When executing attest () of SafetyNet Attestation API, apkPackageName is obtained as a parameter.</p>
<p>I ran this API several times.</p>
<p>As a result, the apkPackageName parameter was missing only once.</p>
<p>In all other execution results, the parameter apkPackageName is present and will not occur again.</p>
<p style=\"min-height: 8pt; padding: 0px;\"> </p>
<p>Why can't I get the apkPackageName when running the SafetyNet Attestation API on a device that has not been
tampered with?</p>
<p style=\"min-height: 8pt; padding: 0px;\"> </p>
<p>device : Kyocera 704KC</p>
<p style=\"min-height: 8pt; padding: 0px;\"> </p>
<p>Regards,</p>
</div><!-- [DocumentBodyEnd:a63392fa-f859-4513-867e-1f3d2714b006] -->
</body>
Would anyone have any pointers on how to proceed from here? My goal is to obtain the text from the content.text object, which I can see on any regular editor, but not in apps script for some reason while using the html format that it returns as is.
Code.gs
function doGet(request) {
return HtmlService.createTemplateFromFile('Page').evaluate();
}
function include(filename) {
var finalRequest = UrlFetchApp.fetch('https://www.cloudconnect.xxx...');
var data = finalRequest.toString().replace("throw 'allowIllegalResourceCall is false.';", "").trim();
data = JSON.parse(data);
var returnedData = [];
for(var i in data.list){
var content = data.list[i];
var content_subject = JSON.stringify(content.subject);
var content_text = JSON.stringify(content.content.text);
returnedData.push(content_subject + "<br />" + "<br />" + textBody(content_text));
}
return returnedData;
}
function textBody(content){ // <-- where the error throws on the content_text object
return HtmlService.createHtmlOutput(content);
}
var entityMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'/': '/',
'`': '`',
'=': '='
};
function escapeHtml(string) {
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
return entityMap[s];
});
}
function myFunction() {
Logger.log(HtmlService
.createTemplateFromFile('Page')
.getCode());
}
Page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('Stylesheet'); ?>
</head>
<body>
<script>
var responseSubject;
var responseContent;
function displayData(responseSubject, responseContent) {
document.getElementById('output').innerHTML = responseSubject + <br> + responseContent + <br>;
}
google.script.run.withFailureHandler(displayData).withSuccessHandler(displayData).include();
</script>
</body>
</html>
Update
I have hit a wall returning the Exception: Cannot call SpreadsheetApp.getUi() from this context. (line 21, file "Code")
Code.gs
function doGet(request) {
return HtmlService.createTemplateFromFile('Page').evaluate();
}
function include(filename) {
var finalRequest = UrlFetchApp.fetch('https://www.cloudconnect.xxx....');
var data = finalRequest.toString().replace("throw 'allowIllegalResourceCall is false.';", "").trim();
data = JSON.parse(data);
var returnedData = [];
for(var i in data.list){
var content = data.list[i];
var contentSubject = JSON.stringify(content.subject);
var contentText = JSON.stringify(content.content.text);
returnedData.push(contentSubject + "<br/>" + "<br/>");
var fixedContent = escapeHtml(contentText);// fixes the malformed Html error
var ui = HtmlService.createHtmlOutput(fixedContent);//the attempt to read the onlick event and load the content text - but it throws the error: Exception: Cannot call SpreadsheetApp.getUi() from this context. (line 21, file "Code")
SpreadsheetApp.getUi().showModelessDialog(ui);
Logger.log("returnedData is: " + returnedData);
}
return returnedData;
}
var entityMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'/': '/',
'`': '`',
'=': '='
};
function escapeHtml(string) {
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
return entityMap[s];
});
}
function myFunction() {
Logger.log(HtmlService
.createTemplateFromFile('Page')
.getCode());
}
//function contentBody(responseContent){ <-- realized I can't do this from a custom function
//var html = responseContent;
//var ui = HtmlService.createHtmlOutput(html);
//SpreadsheetApp.getUi().showModelessDialog(ui);
//}
Page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('Stylesheet'); ?>
<script>
var responseSubject;
var responseContent;
function displaySubjects(responseSubject) {
document.getElementById('output').addEventListener('click', getContentBody).innerHTML = responseSubject;
}
google.script.run.withFailureHandler(displaySubjects).withSuccessHandler(displaySubjects).include();
//function displayContentText(responseContent){
//document.getElementById('projection').innerHTML = responseContent;
//}
//google.script.run.withFailureHandler(displayContentText).withSuccessHandler(displayContentText).contentBody();
</script>
</head>
<body>
<p id = "output"></p>
<p id = "projection"></p>
</body>
</html>
My goal here is to add a click listener to the subjects and have them load the content text through the Html service.
Any help would be highly appreciated please.
Cheers!
This works:
function htmltest() {
var html='<body><!--[DocumentBodyStart:a63392fa-f859-4513-867e-1f3d2714b006]--><div class="jive-rendered-content"><p>Hi,team!</p><p style="min-height:8pt;padding:0px;"> </p><p>When executing at test() of Safety NetAttestationAPI, apkPackageName is obtained as a parameter.</p><p>I ran this API several times.</p><p>As a result,the apkPackageName parameter was missing only once.</p><p>In all other execution results,the parameter apkPackageName is present and will not occur again.</p><p style="min-height:8pt;padding:0px;"> </p><p>Whycan\'t I get the apkPackageName when running the Safety NetAttestation API on a device that has not been tampered with?</p><p style="min-height:8pt;padding:0px;"> </p><p>device:Kyocera704KC</p><p style="min-height:8pt;padding:0px;"> </p><p>Regards,</p></div><!--[DocumentBodyEnd:a63392fa-f859-4513-867e-1f3d2714b006]--></body>';
var ui=HtmlService.createHtmlOutput(html).setHeight(500);
SpreadsheetApp.getUi().showModelessDialog(ui, "HTML Test");
}
Here's what I get when I run it just that way it is.

Injecting a custom element in HTML5 then retrieving its value using XPath comes back blank

I'm injecting an XML string generated from a web service, then trying to use XPath to query the attribute values using the following code.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>tox-js</title>
</head>
<body>
<script>
//
// -----------------------------------------------
// tox element
class Tox extends HTMLElement
{
constructor(url)
{
super();
fetch(url)
.then((response)=>
{
console.log("status: "+response.status);
return response.text();
})
.then((text)=>
{
console.log("text: "+text);
try
{
var dp = new DOMParser();
var xmlDOM = dp.parseFromString(text, "text/xml");
this.appendChild(xmlDOM.documentElement);
return true;
}
catch(err)
{
console.log("err: "+err.message);
return false;
}
})
.then((ok)=>
{
if (ok)
{
try
{
var xpe = new XPathEvaluator();
var txt = xpe.evaluate("//tox-js/example/#timestamp",document,null,XPathResult.STRING_TYPE,null);
console.log("//tox-js/example/#timestamp: "+txt.stringValue);
txt = xpe.evaluate("//tox-js/example/#feedback",document,null,XPathResult.STRING_TYPE,null);
console.log("//tox-js/example/#feedback: "+txt.stringValue);
}
catch(err)
{
console.log("err: "+err.message);
}
}
else
console.log("not ok");
}
);
}
}
//
// -----------------------------------------------
// register our element with the DOM
customElements.define('tox-js',Tox);
//
// -----------------------------------------------
// create an instance and add it to the body
document.body.appendChild(new Tox('http://localhost:8080/tox/example.test.formatted?in_mask=YYYYMMDD'));
// -----------------------------------------------
//
</script>
</body>
</html>
The result has the custom element injected.
<html lang="en">
<head>...</head>
<body>
<script>...</script>
<tox-js>
<example timestamp="20180103142036" feedback="ok">20190103</example>
</tox-js>
</body>
<html>
The console log confirms the return status and XML, but the result of the XPath is blank.
[Log] status: 200 (toxElement3.html, line 20)
[Log] text: <example timestamp="20190103142036" feedback="ok">20190103</example> (toxElement3.html, line 25)
[Log] //tox-js/example/#timestamp: (toxElement3.html, line 47)
[Log] //tox-js/example/#feedback: (toxElement3.html, line 49)
Where have I gone wrong? This should not be a timing issue since I'm using .then to wait for the previous step.
Seems it is related to the namespaces.
The following XPath works for me:
//tox-js/*[local-name()='example']/#timestamp
Check this answer:
XPath Doesn't Work in Dynamic HTML-Document
Also you can use document.createElement() or insertAdjacentHTML() to create element from text as described here: Creating a new DOM element from an HTML string using built-in DOM methods or Prototype
In this case your XPath will work as expected.
<html lang="en">
<head></head>
<body>
<script>
window.addEventListener('load', () => {
var text = `<example timestamp="20180103142036" feedback="ok">20190103</example>`;
var el = document.getElementsByTagName('tox-js')[0];
el.insertAdjacentHTML('afterbegin', text);
var xpe = new XPathEvaluator();
var txt = xpe.evaluate("//tox-js/example/#timestamp",document,null,XPathResult.STRING_TYPE,null);
console.log(`//tox-js/example/#timestamp: ${txt.stringValue}`);
});
</script>
<tox-js>
</tox-js>
</body>
<html>
P.S. I can't explain why the problem happens when using DOMParser. Maybe there are different namespaces for document and DOMParser. So if somebody has more details, feel free to extend the answer.
From the provided example...
var dp = new DOMParser();
var xmlDOM = dp.parseFromString(text, "text/xml");
this.appendChild(xmlDOM.documentElement);
...becomes...
this.insertAdjacentHTML('afterbegin', text);

Contents of a spreadsheet are not displayed in the deployed Apps Script webapp

I've tried to do an example of the 3rd tutorial on this ctrlq page, in which we display the content of a spreadsheet on a web page. Here are my files which I simply entered - I didn't activate anything, I just did Publish -> Deploy as web app
I expect to see all of the spreadsheet's values, but instead nothing is shown:
Code.gs
function doGet() {
var html = HtmlService.createTemplateFromFile("index").evaluate();
html.setTitle("Dynamic Webpage");
return html;
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.getContent();
}
function getData(){
var sheet = SpreadsheetApp.openById("1k_kj98U__0Bk44gh0qRFpaVx0ru3sN1pSPGiMQwimxo").getSheets()[0];
return sheet.getDataRange().getValues();
}
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<?!= include('script_js'); ?>
<body>
<div id="data"></div>
</body>
</html>
script_js.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
window.onload = function(){
google.script.run.withSuccessHandler(showData).getData();
}
function showData(data){
var html = "";
for (var i=0; i<data.length; i++) {
html += "<br>" + data[i].join(":");
}
document.getElementById("data").innerHTML = html;
}
</script>
</body>
</html>
Link to the script project
EDIT as #tehhowch pointed out his answer is the correct solution here.
For your case you should make these changes, getData():
function getData(){
var sheet = SpreadsheetApp.openById("1k_kj98U__0Bk44gh0qRFpaVx0ru3sN1pSPGiMQwimxo").getSheets()[0];
return JSON.stringify(sheet.getDataRange().getValues()); // return value as Json
}
And showData(data):
function showData(data) {
var arr = JSON.parse(data);
var html = "";
for (var i=0; i < arr.length; i++) {
html += "<br>" + arr[i].join(":");
}
document.getElementById("data").innerHTML = html;
}

XMLHttpRequest error for the Viewer

I use the following HTML file to test the Headless Viewer of Autodesk Forge. The test url will look like:
http://localhost:8080/HeadlessViewer.html?token={{Bearer}}&urn={{base64URN}}
The token has scope=data:read, urn is base64 format.
<html>
<head>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no" />
</head>
<body>
<div id="MyViewerDiv"></div>
<!-- The Viewer JS -->
<script src="https://developer.api.autodesk.com/viewingservice/v1/viewers/three.min.js?v=v2.10.*"></script>
<script src="https://developer.api.autodesk.com/viewingservice/v1/viewers/viewer3D.js?v=v2.10.*"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<!-- Developer JS -->
<script>
function getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
function initViewer(token, urn) {
var viewerApp;
var options = {
env: 'AutodeskProduction',
accessToken: token
};
var documentId = atob(urn); // 'urn:<YOUR_URN_ID>';
Autodesk.Viewing.Initializer(options, onInitialized);
function onInitialized() {
viewerApp = new Autodesk.Viewing.ViewingApplication('MyViewerDiv');
viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Viewer3D);
viewerApp.loadDocument(documentId, onDocumentLoaded);
}
function onDocumentLoaded(lmvDoc) {
var modelNodes = viewerApp.bubble.search(av.BubbleNode.MODEL_NODE); // 3D designs
var sheetNodes = viewerApp.bubble.search(av.BubbleNode.SHEET_NODE); // 2D designs
var allNodes = modelNodes.concat(sheetNodes);
if (allNodes.length) {
viewerApp.selectItem(allNodes[0].data);
if (allNodes.length === 1) {
alert('This tutorial works best with documents with more than one viewable!');
}
} else {
alert('There are no viewables for the provided URN!');
}
}
}
$(document).ready(function () {
var url = window.location.href,
token = getParameterByName('token', url),
urn = getParameterByName('urn', url);
initViewer(token, urn);
});
</script>
</body>
</html>
However, it stops at the exception XMLHttpRequest.responseText. Please see the attached image: Error image
I tried your code just replacing the "accessToken: <>" and "var documentId = <>" and worked fine. Looking at your code, I believe the problem may be at the following line:
var documentId = atob(urn); // 'urn:<YOUR_URN_ID>';
The atob function will decode the string, which means it will not be on Base64. But the documentId should be like:
var documentId = 'urn:c29tZSByYW5kb20gd29yZHMgaGVyZQ==';
Please make sure the documentId is properly formed.
Finally, note the Viewer requires URL Safe encoding. Consider encoding on server (safer to transmit) or doing it on client-side, see this answer.