My issue is, I'm using the yiono SCRIPT sql library and trying to integrate it with HTML but am having trouble with 2 pieces. Everything else is working beautifully.
For example
I want to make an HTML form to update the 'Pro' value on the row that 'ID' = '1'
It works beautifully when I run the function in IDE, but I don't know the best way to put these in as variables from an HTML page. I tried some silliness with GET requests but couldn't get it to work.
function update_row(){
var SQL = new gSQL();
SQL.DB('*redacted*').TABLE('DAILY-DATA').UPDATE('Pro').WHERE('ID', '=', '1').VALUES('KAOS').setVal();
}
Problem 1: Get form input into .WHERE('ID', '=','from_html_form') and I'd like to do it within the Google environment by way of web app.
Minimal Reproducible Example
Here is the function
Here is the result
Replace
function update_row(){
var SQL = new gSQL();
SQL.DB('*redacted*').TABLE('DAILY-DATA').UPDATE('Pro').WHERE('ID', '=', '1').VALUES('KAOS').setVal();
}
by
function update_row(input = '1'){
var SQL = new gSQL();
SQL.DB('*redacted*')
.TABLE('DAILY-DATA')
.UPDATE('Pro')
.WHERE('ID', '=', input)
.VALUES('KAOS')
.setVal();
}
Main changes
added a parameter with a default value
Replaced a literal by the parameter
NOTES: The breaklines are not really required, it's a matter of programming style.
Add the below simple trigger to a .gs file in your Google Apps Script project.
function doGet(e){
const html = `
<input type="number" />
<button onClick="myFunction();">Submit</button>
<script>
function myFunction(){
google.script.run
.withSuccessHandler(()=> {
const div = document.createElement('div');
div.innerText = 'Done!'
document
.body
.appendChild(div)
})
.update_row(document.querySelector('input').value);
}
</script>`
return HtmlService.createHtmlOutput(html);
}
To test this you will have to deploy as web app. Please follow the instructions for this on https://developers.google.com/apps-script/guides/web.
Resources
https://developers.google.com/apps-script/guides/web
https://developers.google.com/apps-script/guides/html/communication?hl=en#forms
Related
I am using js to get the HTML for my websites navbar. instead of having to paste it on each page,
that part works great. the issue is afterwards i create a script and link element, to provide the javascript and the css file that goes with the navbar. using brackets application it works. but in real world application i'm getting error 404, i've checked the location and it seams to be correct.
also. is there a way to tell when the html from the fetch method is completed? i have a set timeout() function of 6ms as without it it's a 50-50 shot of loading the js file before the html. like a window.onload() command.
//Getting include attribute value
function getHTML() {
var includes = document.getElementsByTagName('include');
for(let i=0; i<includes.length; i++){
let include = includes[i];
//Loading include src value
load_file(includes[i].attributes.src.value, function(text){
include.insertAdjacentHTML('afterend', text);
include.remove();
});
}
const body = document.getElementsByTagName('body')[0],
script = document.createElement("script"),
head = document.getElementsByTagName('head')[0],
link = document.createElement('Link');
link.setAttribute('rel',"styleSheet")
link.setAttribute('href','/wont-work');
head.appendChild(link)
setTimeout(()=> {
script.setAttribute("src","/Navbar.js");
script.setAttribute("type","text/javaScript")
body.appendChild(script);
},6);
}
function load_file(filename, callback) {
fetch(filename).then(response => response.text()).then(text => callback(text));
console.log('file loaded')
}
window.addEventListener("load", getHTML);
expecting the CSS and Javascript to NOT be 404
I have a problem with updating HTML element http://www.hororsf.iz.rs/. The element class is "date-header"
I tried Jquery function triggered on load
$( "date-header" ).replaceWith( "<h2>New heading</h2>" );
I tried this in Jquery:
<script language='text/javascript'>
function cirtolat(){
$('date-header').each(function() {
var text = $(this).text();
$(this).text(text.replace('петак', 'doll'));
});
}
</script>
<body onload="cirtolat();">
And this in Javascript
document.body.innerHTML = document.body.innerHTML.replace(/hello/g, 'hi');
I used another words this is just example. I tried this also: (every example provided here I put inside onload function).
var str = document.getElementById("demo").innerHTML;
var res = str.replace("Microsoft", "W3Schools");
document.getElementById("demo").innerHTML = res;
I first tried does this onload function work with alert and it worked. I need this to work on blogger platform so I don't have access to server side access only client side with jquery or javascript.
If I had access for sever side I would find wordpress language folder where he stores date array and replace all values with needed.
So I need to replace all occurrences of strings
децембар/новембар/октобар/септембар/август/јул/јун/мај/април/март/фебруар/јануар/
with
decembar/novembar/oktobar/septembar/avgust/jul/jun/maj/april/mart/februar/januar
days:
понедељак/уторак/среда/четвртак/петак/субота/недеља/
with
ponedeljak/utorak/sreda/četvrtak/petak/subota/nedelja/
I don't understand why standard methods of javascript and jquery I used on non-blogger sites don't work.
I´m trying to get the elements from a web page in Google spreadsheet using:
function pegarAsCoisas() {
var html = UrlFetchApp.fetch("http://www.saosilvestre.com.br").getContentText();
var elements = XmlService.parse(html);
}
However I keep geting the error:
Error on line 2: Attribute name "itemscope" associated with an element type "html" must be followed by the ' = ' character. (line 4, file "")
How do I solve this? I want to get the H1 text from this site, but for other sites I´ll have to select other elements.
I know the method XmlService.parse(html) works for other sites, like Wikipedia. As you can see here.
The html isn't xml. And you don't need to try to parse it. You need to use string methods:
function pegarAsCoisas() {
var urlFetchReturn = UrlFetchApp.fetch("http://www.saosilvestre.com.br");
var html = urlFetchReturn.getContentText();
Logger.log('html.length: ' + html.length);
var index_OfH1 = html.indexOf('<h1');
var endingH1 = html.indexOf('</h1>');
Logger.log('index_OfH1: ' + index_OfH1);
Logger.log('endingH1: ' + endingH1);
var h1Content = html.slice(index_OfH1, endingH1);
var h1Content = h1Content.slice(h1Content.indexOf(">")+1);
Logger.log('h1Content: ' + h1Content);
};
The XMLService service works only with 100% correct XML content. It's not error tolerant. Google apps script used to have a tolerant service called XML service but it was deprecated. However, it still works and you can use that instead as explained here: GAS-XML
Technically HTML and XHTML are not the same. See What are the main differences between XHTML and HTML?
Regarding the OP code, the following works just fine
function pegarAsCoisas() {
var html = UrlFetchApp
.fetch('http://www.saosilvestre.com.br')
.getContentText();
Logger.log(html);
}
As was said on previous answers, other methods should be used instead of using the XmlService directly on the object returned by UrlFetchApp. You could try first to convert the web page source code from HTML to XHTML in order to be able to use the Xml Service Service (XmlService), use the Xml Service as it could work directly with HTML pages, or to handle the web page source code directly as a text file.
Related questions:
How to parse an HTML string in Google Apps Script without using XmlService?
What is the best way to parse html in google apps script
Try replace itemscope by itemscope = '':
function pegarAsCoisas() {
var html = UrlFetchApp.fetch("http://www.saosilvestre.com.br").getContentText();
html = replace("itemscope", "itemscope = ''");
var elements = XmlService.parse(html);
}
For more information, look here.
It is a web app, using Google Apps Script, running as the user accessing the app.
We have custom data and code for some users.
That custom information is in a text file within the developer's Google Drive, with only View access from the specific user.
The content of that text file could be like below dummy code:
var oConfig = {
some : "OK",
getinfo : function (s) {
return this.some + s;
}
}
In order to get that custom data / code into the app, we can use eval() as shown below:
var rawjs = DriveApp.getFileById(jsid).getBlob().getDataAsString();
eval(rawjs);
Logger.log(oConfig.getinfo("?")); // OK?
My questions are:
Is there a better way to achieve this goal than eval()?
Is eval() secure enough in this case, considering that the text file is only editable by the developer?
Thanks, Fausto
Well, it looks secure enough. But using eval has other problems, like making it difficult to debug your code, and possibly some other problems.
If you're generating such custom data within your code, I imagine the variety of such customizations is enumerable. If so, I'd leave the code within your script and save in Drive just data and use indicators (like function variants names) of how to rebuild the config object in your script. For example:
function buildConfig(data) {
var config = JSON.parse(data); //only data, no code
config.getInfo = this[config.getInfo]; //hook code safely
return config;
}
function customInfo1(s) { return this.some + s; }
function customInfo2(s) { return s + this.some; }
function testSetup() {
//var userData = DriveApp.getFileById(jsid).getBlob().getDataAsString();
var userData = '{"some":"OK", "getInfo":"customInfo1"}'; //just for easier testing
var config = buildConfig(userdata); //no eval
//let's test it
Logger.log(config.getInfo('test'));
}
It seems secure. But, it will make your execution process slower if you have large data in your text file.
I would still suggest to use JSON.parse() instead of eval() to parse your custom data/code.
{
some : "OK",
getinfo : "function(s){return this.some +\" \"+ s;}"
}
var rawjs = DriveApp.getFileById(jsid).getBlob().getDataAsString();
var oConfig = JSON.parse(rawjs, function(k,v){//put your code here to parse function}); // avoid eval()
Logger.log(oConfig.getinfo("?"));
Following this SO solution here to notify clients of a click event in a PDF document, how is it possible to notify the client when the PDF gets submitted by the client using this.myPDF.submitForm("localhost/Handler.ashx?r=2) function?
The PDF File is created inside a user control then rendered into a HTML object:
string container = ("<object data='/myfile.pdf' type='application/pdf'></object>");
The JS file attached to the PDF is done like this:
var webClient = new WebClient();
string htmlContent = webClient.DownloadString(fileurl + "pdf_script.js");
PdfAction action = PdfAction.JavaScript(htmlContnent, pdfstamper.Writer);
pdfstamper.Writer.SetOpenAction(action);
And the content of the js file:
this.disclosed = true;
if (this.external && this.hostContainer) {
function onMessageFunc(stringArray) {
try {
this.myPDF.submitForm("http://localhost/Handler.ashx?EmpNo=12345" + "#FDF", false);
}
catch (e) {
}
}
function onErrorFunc(e) {
console.show();
console.println(e.toString());
}
try {
if (!this.hostContainer.messageHandler);
this.hostContainer.messageHandler = new Object();
this.hostContainer.messageHandler.myPDF = this;
this.hostContainer.messageHandler.onMessage = onMessageFunc;
this.hostContainer.messageHandler.onError = onErrorFunc;
this.hostContainer.messageHandler.onDisclose = function () { return true; };
}
catch (e) {
onErrorFunc(e);
}
}
When the submitForm call is made the PDF contents (form fields) get saved successfully and an alert is displayed in the PDF by doing this:
message = "%FDF-1.2
1 0 obj
<<
/FDF
<<
/Status("Success!")
>>
>>
endobj
trailer
<</Root 1 0 R>>
%%EOF");
return message;
What I'm trying to do is to get the PDF to callback the client after the form submit call sent from this client, a way to acknowledge the client that the form has been submitted, not in a form of an alert, but rather, a way to trigger a function in the host (the container, an iframe, object...etc).
The FDF response you used was unknown to me, so I've learned something new from your question. I've studied the AcroJS Reference and the FDF specification in the PDF Reference, and now I have a better understanding of what your code does. Thank you for that.
I assume that you already know how to trigger a JavaScript message in an HTML file using a JavaScript call from a PDF. See the createMessageHandler() in the JavaScript Communication between HTML and PDF article.
I interpret your question as: "How to I invoke this method after a successful submission of the data?"
If there's a solution to this question, it will involve JavaScript. I see that one can add JavaScript in an FDF file, but I'm not sure if that JavaScript can 'talk to' HTML. I'm not sure if you can call a JavaScript function in your initial PDF from the FDF response. If it's possible, you should add a JavaScript entry to your PDF similar to the /Status entry.
The value of this entry is a dictionary, something like:
<<
/Before (app.alert\("before!"\))
/After (app.alert\("after"\))
/Doc [/MyDocScript1, (myFunc1\(\)),
/MyDocScript2, (myFunc2\(\))
>>
In your case, I would remove the /Before and /Doc keys. I don't think you need them, I'd reduce the dictionary to:
<<
/After (talkToHtml\(\))
>>
Where talkToHtml() is a method already present in the PDF:
function talkToHtml() {
var names = new Array();
names[0] = "Success!";
try{
this.hostContainer.postMessage(names);
}
catch(e){
app.alert(e.message);
}
}
I don't know if this will work. I've never tried it myself. I'm basing my answer on the specs.
I don't know if you really need to use FDF. Have you tried adding JavaScript to your submitForm() method? Something like:
this.myPDF.submitForm({
cURL: "http://localhost/Handler.ashx?EmpNo=12345",
cSubmitAs: "FDF",
oJavaScript: {
Before: 'app.alert("before!")',
After: 'app.alert("after")',
Doc: ["MyDocScript1", "myFunc1()",
"MyDocScript2", "myFunc2()" ]
}
});
This will only work if you submit as FDF. I don't think there's a solution if you submit an HTML query string.
In case you're wondering what MyDocScript1 and MyDocScript2 are:
Doc defines an array defining additional JavaScript scripts to be
added to those defined in the JavaScript entry of the document’s name
dictionary. The array contains an even number of elements, organized
in pairs. The first element of each pair is a name and the second
is a text string or text stream defining the script corresponding
to that name. Each of the defined scripts is added to those already
defined in the name dictionary and then executed before the script
defined in the Before entry is executed. (ISO-32000-1 Table 245)
I'm not sure if all of this will work in practice. Please let me know either way.