Currently I'm using an example to create an upload function for my webpage on Google Apps Script. This is the code:
Code.gs
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('form.html');
}
function uploadFiles(form) {
try {
var dropbox = "Test Files";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + form.myName);
return "File uploaded successfully " + file.getUrl();
} catch (error) {
return error.toString();
}
}
form.html
<form id="myForm">
<input type="text" name="myName" placeholder="Your name..">
<input type="file" name="myFile">
<input type="submit" value="Upload File"
onclick="this.value='Uploading..';
google.script.run.withSuccessHandler(fileUploaded)
.uploadFiles(this.parentNode);
return false;">
</form>
<div id="output"></div>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
input { display:block; margin: 20px; }
</style>
This code works fine by itself but when I try and implement it on my webpage with the current existing code: https://jsfiddle.net/05nmqy63/
It won't work like shown in the example. The example uploads a file into a folder in my Google Docs but when put into my code the page changes but it doesn't upload anything nor does it say the file has been submitted.
How do I fix this? Or is there an easier way to implement an upload button? (I want the submit order button to be able to function as the upload button)
Figured out the problem to my question after finding out what was wrong. The error I received was this: Uncaught InvalidArgumentError: Failed due to illegal value in property: 0
This error was solved by another person on this forum: google.script.run not working: Uncaught InvalidArgumentError: Failed due to illegal value in property: 0
Related
I am working through an old project and trying to fix a few bugs.
I have a file upload in HTML
function updateImage() {
circleArray = [];
newPic = `id="taco" width="300" height="300" src="${$(
"#myFile"
).val()}" alt="prime.png"`;
$("#hide").empty();
$("#hide").append(`<img ${newPic}>`);
makeCanvas();
}
<form>
<input type="file" id="myFile" name="filename">
<button id='submit'>Submit</button>
</form>
When I click the submit button I have a function that should update the image displayed with the newly uploaded image.
It seems like the file is uploaded but I am accessing it incorrectly.
I see the following error
GET c:\fakepath\IMG_0544.jpg net::ERR_UNKNOWN_URL_SCHEME
Consider the following.
$(function() {
function updateImage() {
var newPic = $("<img>", {
id: "taco",
alt: "prime.png"
}).css({
width: 300,
height: 300
});
var myFile = $("#myFile")[0].files[0];
var reader = new FileReader();
reader.onload = function(event) {
newPic.attr("src", event.target.result);
$("#hide").empty().append(newPic);
};
reader.readAsDataURL(myFile);
//makeCanvas();
}
$("form").submit(function(event) {
event.preventDefault();
updateImage();
return false;
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<input type="file" id="myFile" name="filename">
<button id='submit'>Submit</button>
</form>
<div id="hide"></div>
This reads the file from the input element and renders it as an Image.
I'm unable to reproduce the problem in your dynamic "code snippet", but it's pretty clear what's happening.
The error GET c:\fakepath\IMG_0544.jpg net::ERR_UNKNOWN_URL_SCHEME means that your browser was trying to access a file on your C:\ drive as though it were a remote URL. You can't do that :)
ONE POSSIBLE SOLUTION: try uploading the image and rendering it as an "embeddd image", per this article:
https://www.thesitewizard.com/html-tutorial/embed-images-with-data-urls.shtml
ANOTHER POSSIBLE SOLUTION: Use FileReader.readAsDataURL():
https://www.tutorialrepublic.com/faq/how-to-preview-an-image-before-it-is-uploaded-using-jquery.php
Try this :
function updateImage() {
circleArray = [];
newPic = `id="taco" width="300" height="300" src="${$("#myFile").get(0).files[0].name}" alt="prime.png"`;
$("#hide").empty();
$("#hide").append(`<img ${newPic}>`);
makeCanvas();
}
I'm using the JSONEditor (https://github.com/josdejong/jsoneditor) to load a json file, make changes and save the file. This works great but it only saves the JSON file to the folder specified according to your browser settings. Here's the demo code (https://github.com/josdejong/jsoneditor/blob/master/examples/04_load_and_save.html):
<!DOCTYPE HTML>
<html>
<head>
<title>JSONEditor | Load and save</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<script src="https://bgrins.github.io/filereader.js/filereader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js"></script>
<style>
html, body {
font: 11pt sans-serif;
}
#jsoneditor {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<h1>Load and save JSON documents</h1>
<p>
This examples uses HTML5 to load/save local files.
Powered by FileReader.js and
FileSaver.js.<br>
Only supported on modern browsers (Chrome, FireFox, IE10+, Safari 6.1+, Opera 15+).
</p>
<p>
Load a JSON document: <input type="file" id="loadDocument" value="Load"/>
</p>
<p>
Save a JSON document: <input type="button" id="saveDocument" value="Save" />
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
var editor = new JSONEditor(document.getElementById('jsoneditor'));
// Load a JSON document
FileReaderJS.setupInput(document.getElementById('loadDocument'), {
readAsDefault: 'Text',
on: {
load: function (event, file) {
editor.setText(event.target.result);
}
}
});
// Save a JSON document
document.getElementById('saveDocument').onclick = function () {
// Save Dialog
fname = window.prompt("Save as...");
// Check json extension in file name
if(fname.indexOf(".")==-1){
fname = fname + ".json";
}else{
if(fname.split('.').pop().toLowerCase() == "json"){
// Nothing to do
}else{
fname = fname.split('.')[0] + ".json";
}
}
var blob = new Blob([editor.getText()], {type: 'application/json;charset=utf-8'});
saveAs(blob, fname);
};
</script>
</body>
</html>
I want to be able to save the file to the web server. Is there any way for me to save the edited JSON file to the web server? I searched and tried to integrate this library with JSONEditor but no joy:
https://abandon.ie/notebook/simple-file-uploads-using-jquery-ajax
I'm not restricted to ajax so I'll consider anything that works!
Thanks for your advice.
John
UPDATED: Here's the controller code chunk.
// POST api/values
public async void Post()
{
string json = await Request.Content.ReadAsStringAsync();
File.WriteAllText(
HttpContext.Current.Server.MapPath("~\\App_Data\\somefile.json"),
json
);
}
I tested this using Postman and it works. What I can't seem to do for the life of me is to now send the edited JSON file to the controller. Here's the modified HTML page where I try unsuccessfully to send the json. For brevity, I'll just add the extra/edited code code:
<form id="form1" method="post" enctype="text/plain" action="http://localhost:1651/api/values">
<input type="file" name="json" id="loadDocument" value="Load"/>
<input type="submit" value="Save" />
</form>
Edited javascript where I try to return the edited json to the form:
document.getElementById('saveDocument').onclick = function () {
return editor.getText();
};
Please help! How do I send the json to the controller?
I initially saw this code online, that allows users to upload files to their google drive through a page. The script automatically creates a folder
//https://script.google.com/d/12EnDFZrsfpBubZ9lM7pnHIsn9M49_vyXm0TLBQ_pyx_ViAJH3HXgkoe9/edit?newcopy=true
So you will notice that initially the codes is supposed to be deployed as a webapp but I tweaked it to make it run on the sidebar. The html part loads fine, you can actually key in all the data, but once you click the upload form, it just returns a blank page. I'm pretty convinced that it's because the click button is not connecting to the script again, making it fail
This is the original code
/* The script is deployed as a web app and renders the form */
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('form.html')
.setSandboxMode(HtmlService.SandboxMode.NATIVE);
// This is important as file upload fail in IFRAME Sandbox mode.
}
/* This function will process the submitted form */
function uploadFiles(form) {
try {
// Name of the Drive folder where the files should be saved
var dropbox = "Database";
;
var folder, folders = DriveApp.getFoldersByName(dropbox);
// Find the folder, create if the folder does not exist
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
// Get the file uploaded though the form as a blob
var blob = form.myFile;
var file = folder.createFile(blob);
// Set the file description as the name of the uploader
file.setName(form.myCode + " " + form.myfilename + " - " + form.myID + " - " + form.myName);
file.setDescription("Uploaded by " + form.myName + " - " + form.myEmail);
// Return the download URL of the file once its on Google Drive
return "File uploaded successfully, please check your drive with this link for confirmation: " + file.getUrl();
} catch (error) {
// If there's an error, show the error message
return error.toString();
}
}
AND THE HTML IS HERE
<!-- Include the Google CSS package -->
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<!-- You can also include your own CSS styles -->
<style>
form { margin: 40px 20px auto; }
input { display:inline-block; margin: 20px; }
</style>
<script>
// The function will be called after the form is submitted
function uploadFile() {
document.getElementById('uploadFile').value = "Uploading File..";
google.script.run
.withSuccessHandler(fileUploaded)
.uploadFiles(document.getElementById("labnol"));
return false;
}
// This function will be called after the Google Script has executed
function fileUploaded(status) {
document.getElementById('labnol').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<!-- This is the HTML form -->
<form id="labnol">
<!-- Text input fields -->
File Upload<br>
<br>
Your Name:<br>
<input type="text" name="myName" placeholder="Your name.."> <br><br>
Email Address: <br>
<input type="email" name="myEmail" placeholder="Your email.."> <br><br>
ID? <br>
<input type="number" name="myID" placeholder="Your ID.."> <br><br>
Upload Code: <br>
<input type="text" name="myCode" placeholder="Your Upload code.."> <br><br>
File Name: <br>
<input type="text" name="myfilename" placeholder="Your File Name"> <br><br>
<!-- File input filed -->
<input type="file" name="myFile">
<!-- The submit button. It calls the server side function uploadfiles() on click -->
<br>
<input type="submit" id="uploadFile" value="Upload File"
onclick="this.value='Uploading..';uploadFile();">
</form>
<!-- Here the results of the form submission will be displayed -->
<div id="output"></div>
So from the original code I tweaked it to replace the top part
function showSidebar() {
var html = HtmlService.createHtmlOutputFromFile('form')
.setTitle('Upload Form')
.setWidth(250);
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showSidebar(html);
}
// This function will process the submitted form
function uploadFile(form) {
try {
// Name of the Drive folder where the files should be saved
var dropbox = "Database";
;
var folder, folders = DriveApp.getFoldersByName(dropbox);
// Find the folder, create if the folder does not exist
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
// Get the file uploaded though the form as a blob
var blob = form.myFile;
var file = folder.createFile(blob);
// Set the file description as the name of the uploader
file.setName(form.myCode + " " + form.myfilename + " - " + form.myID + " - " + form.myName);
file.setDescription("Uploaded by " + form.myName + " - " + form.myEmail);
// Return the download URL of the file once its on Google Drive
return "File uploaded successfully, please check your drive with this link for confirmation: " + file.getUrl();
} catch (error) {
// If there's an error, show the error message
return error.toString();
}
}
So I basically replaced the top part with a script to load the sidebar and the html "form" but the error appears is that upon clicking upload, it does not work.
I'm guessing it's this part
<input type="submit" id="uploadFile" value="Upload File"
onclick="this.value='Uploading..';uploadFile();">
since onClick, it should run the function uploadFile() but it does not work.
I've been trying to figure this out for quite some time but can't seem to make this last part work. So I'm here asking if anyone can help me solve this coding issues
Based from this documentation: HTML Service: Communicate with Server Functions
google.script.run is an asynchronous client-side JavaScript API that allows HTML-service pages to call server-side Apps Script functions. The following example shows the most basic functionality of google.script.run — calling a function on the server from client-side JavaScript.
Check how the Form communicates with Apps Script. If you call a server function with a form element as a parameter, the form becomes a single object with field names as keys and field values as values. The values are all converted to strings, except for the contents of file-input fields, which become Blob objects.
Here is there sample code:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// Prevent forms from submitting.
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
}
function updateUrl(url) {
var div = document.getElementById('output');
div.innerHTML = 'Got it!';
}
</script>
</head>
<body>
<form id="myForm" onsubmit="handleFormSubmit(this)">
<input name="myFile" type="file" />
<input type="submit" value="Submit" />
</form>
<div id="output"></div>
</body>
</html>
It would be best if you simplify how you call the function in an OnSubmit event. Also, you can debug you script using Execution Transcript, which is a record of each call to a Google Apps Script service that is made while the script runs.
Hope this helps!
Can not pass parameter from Page.html file to google.script.run function
<input type="button" value="Load Norm"
onclick="google.script.run
.loadNormFromSidebar('10A')" />
Then I am expecting to have 10A as parameter to my loadNormFromSidebar function:
function loadNormFromSidebar(normNr) {
Logger.log(normNr);
var jobNr = params.getDescriptionSheet().getRange(params.jobNrCell).getValue();
normNr=jobNr+'-'+normNr;
loadNormWithNr(normNr);
}
Any ideas why normNr is not passed from html to gs?
Log output file is empty.
I can not reproduce the problem. In my test everything works as expected.
Index.html
<html>
<body>
<input type="button"
value="Load Norm"
onclick="google.script.run.loadNormFromSidebar('10A')" />
</body>
</html>
Code.gs
function doGet(e) {
var template = HtmlService.createTemplateFromFile('Index');
return template.evaluate()
.setTitle('Web App Window Title')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function loadNormFromSidebar(normNr) {
Logger.log(normNr);
/*
var jobNr = params.getDescriptionSheet().getRange(params.jobNrCell).getValue();
normNr=jobNr+'-'+normNr;
loadNormWithNr(normNr);
*/
}
View -> Logs
Have you created a new version of your application and published that version?
Found mistake. Above code is part of library Estimating. In local file I had
function loadNormFromSidebar() {
Estimating.loadNormFrimSidebar()
}
where should be
function loadNormFromSidebar(normNr) {
Estimating.loadNormFrimSidebar(normNr)
}
so I'm trying to set up upload size limit, but it has been unsuccessful.
I have included the code with explanations, please hava a look and I would be very thankfull if you could help me.
More information on wha I needм help with is after the " // "
Here's the code: `
<html>
<p id="check"></p>
//ok so this part of <script> sends the user to "email.html"
<script type="text/javascript">
function getFile(){
document.getElementById("file").click();
}
function sub(obj){
var file = obj.value;
document.myForm.submit();
}
</script>
//here's the code for the button to upload a file (or image in my case)
<form action="e-mail.php" method="post" enctype="multipart/form-data" name="myForm">
<div id="yourBtn" onclick="getFile()">Yes</div>
<div style="text-align: center; overflow: hidden;">
<input type="file" value="upload" id="file" accept="image/*"
onchange="sub(this)"
size="1" style="margin-top: -50px;" "margin-left:-410px;" "-moz-opacity: 0;
"filter:
alpha(opacity=0);" "opacity: 0;" "font-size: 150px;" "height: 100px;">
</div>
</form>
<script>
var attachement = document.getElementById('file');
attachement.onchange = function() {
var file = attachement.files[0];
if (file.size < 1000000) {
function sub(obj){return true; }
//ok so here's the problem,
when I include this code between
'script' the user is not taken
to "e-mail.html" anymore... please help!!!
else { return false;}
}
}
</script>
</html> `
Thanks a lot:)
To go to a different page when the file is too big, you can assign the new URL to document.location. Note that the URL should be absolute (i.e. http://.../email.html).
I suggest to display an error when the file is too big and simply not submit the page. Otherwise, the user will see the new page and believe that everything was all right.
Also note that you need to do the same check on the server because an attacker might just create a POST request from scratch (without using the code from your page) to send files of arbitrary size to your server.
Because the funtion inside of the onchange is not global. It is only available to the onchange.
would would need to change it to
window.sub = function (obj){return true; }
BUT the flaw with this is the user can change the file a second time and submit since you just removed the return false. You could either add it back in on the else OR you can do validation when the form is submitted and not onchange.