I apologize in the advance as I am a total beginner.
I have a pre-existing html form with text fields. I need to have a button that will allow me to upload a txt file (since when trying to look for answer about this, I learned javascript can't just access a file from my PC without me actively uploading it). Then I need the values from this txt file inserted into the text fields (for example, the form has: name, last name, phone etc - and the file will fill out this info).
I am going crazy trying to collect bits and pieces from other people's questions. any help would be greatly appreciated!
it depends on how you would like to have this handled, there are basically two options:
File Upload and page redirect
you could provide a file upload form to upload your textfile, redirect to the same page via form submission, handle the data on serverside (e.g. parse the file and get the values out of it) and let the server inject the values as default properties for the form file which is returned to the browser
XMLHttpRequest File Upload
in modern browsers, the native xhr object supports an upload property, so you could send the file via that upload property. it has to be sent to a serverside script that parses the file and returns the values in a fitting format, e.g. json (which would look like this: {'name':'somename', 'lastName':'someothername'}). then you have to register an eventlistener on completion of this upload (e.g. onload) and set these values on javascript side.
check this out for XMLHttpRequest upload (better solution in my opinion): https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Submitting_forms_and_uploading_files
edit:
well, the easiest solution would be just to provide a textfield and paste the content of the file into this field, hit a button and the content is parsed. then you wouldn't rely on network traffic or even a serverside handling, but could do everything with javascript, e.g. like this:
dom:
<textarea id="tf"></textarea>
<button id="parse">fill form!</button>
js:
var tf = document.getElementById("tf");
document.getElementById("parse").addEventListener("click", function(){
var formData = JSON.parse(tf.value);
//if your textfile is in json format, the formData object now has all values
});
edit: from the link i posted in the comments:
<!-- The HTML -->
<input id="the-file" name="file" type="file">
<button id="sendfile">send</button>
and
document.getElementById('sendfile').addEventListener("click", function(){
var fileInput = document.getElementById('the-file');
var file = fileInput.files[0];
var formData = new FormData();
formData.append('file', file);
var xhr = new XMLHttpRequest();
// Add any event handlers here...
xhr.open('POST', '/upload/path', true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var values = JSON.parse(xhr.responseText);
//these are your input elements you want to fill!
formNameInput.setAttribute('value', values.name);
formFirstNameInput.setAttribute('value', values.firstName);
}
}
xhr.send(formData);
});
as already said, your serverside has to parse the file and respond with json
Related
Short version
I have a webapp using Magnolia, I need to upload a comment with posibility of multiple files, I want to use AJAX, before saving the files as assets I want to be able to check the user's permission, I figured I need a custom Java-based REST endpoint, I made it work, but I have issues saving "jcr:data" into an asset.
Long version
I have a webapp, I have registered users (using PUR), I have different roles for users (for simplicity let's say User and Editor) and I have a Post and a Comment content types. Every User can create a Post and add files, every Post holds the creator's UUID, array of Comment UUIDs and array of file UUIDs (from Assets app), every Post has a comment section and every Comment can have files attached (zero or multiple) to it. Every Editor can post a comment to every Post, but Users can only post comments to their own Posts.
My form for comments looks something like this:
<form action="" method="post" id="comment-form" enctype="multipart/form-data">
<input type="file" name="file" id="file" multiple />
<textarea name="text"></textarea>
<button type="button" onclick="sendComment();">Send</button>
</form>
I tried using Javascript model to process the data and I was able to save the asset correctly, however only one. I couldn't access the other files in the model.
I tried solving it (and improving user experience) by using AJAX and a REST endpoint. I opted not to use the Nodes endpoint API, because I didn't know how to solve the permission issue. I know I can restrict access to REST for each role, but not based on ownership of the Post. So I created my own Java-based endpoint (copied from documentation).
In the sendComment() function in Javascript I create an object with properties like name, extension, mimeType, ..., and data. I read in the documentation that you should send the data using the Base64 format, so I used FileReader() to accomplish that:
var fileObject = {
// properties like name, extension, mimeType, ...
}
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
// this part is easy
};
xhttp.open("PUT", "http://localhost:8080/myApp/.rest/assets/v1/saveAsset", true);
xhttp.setRequestHeader("Content-type", "application/json");
var reader = new FileReader();
reader.onload = function() {
fileObject.data = reader.result;
// I also tried without the 'data:image/png;base64,' part by reader.result.split(",")[1];
xhttp.send(JSON.stringify(fileObject));
};
reader.readAsDataURL(file); //where file is the value of the input element.files[i]
In Java I created a POJO class that has the same properties as the javascript object. Including a String data.
The code for the endpoint looks like this:
public Response saveAsset(Asset file) {
// Asset is my custom POJO class
Session damSession;
Node asset;
Node resource;
try {
damSession = MgnlContext.getJCRSession("dam");
asset = damSession.getRootNode().addNode(file.getName(), "mgnl:asset");
asset.setProperty("name", file.getName());
asset.setProperty("type", file.getExtension());
resource = asset.addNode("jcr:content", "mgnl:resource");
InputStream dataStream = new ByteArrayInputStream(file.getData().getBytes());
ValueFactory vf = damSession.getValueFactory();
Binary dataBinary = vf.createBinary(dataStream);
resource.setProperty("jcr:data", dataBinary);
resource.setProperty("fileName", file.getName());
resource.setProperty("extension", file.getExtension());
resource.setProperty("size", file.getSize());
resource.setProperty("jcr:mimeType", file.getMimeType());
damSession.save();
return Response.ok(LinkUtil.createLink(asset)).build();
} catch (RepositoryException e) {
return Response.ok(e.getMessage()).build(); //I know it's not ok, but that's not important at the moment
}
}
The asset gets created, the properties get saved apart from the jcr:data. If I upload an image and then download it either by the link I get as a response or directly from the Assets app, it cannot be opened, I get the format is not supported message. The size is 0, image doesn't show in the Assets app, seems like the data is simply not there, or it's in the wrong format.
How can I send the file or the file data to the Java endpoint? And how should I receive it? Does anybody know what am I missing? I honestly don't know what else to do with it.
Thank you
The input stream had to be decoded from Base64.
InputStream dataStream = new ByteArrayInputStream(Base64.decodeBase64(file.getData().getBytes()));
...and it only took me less than 3 months.
Noticed it after going through the source code for REST module that for unmarshalling Binary Value it had to be encoded to Base64, so I tried decoding it and it started to work.
I have a JavaScript Pivot table that displays data to the user. The user can select the columns/rows etc. I've added an export to Excel button, that performs an ajax post with the current data/view of the pivot table (json data). It posts the data to my server that converts that to an Excel file.
Creating the file all works well, but my problem is getting the file to the user. From what I've read I can't send a file to a user after an ajax post.
I'm happy to use a plain html post (in fact it is what I want since I can redirect the user to the file), but I don't know how to include the pivot table data as part of the post since it is not a form.
I know I can save the file locally and send a url back but this complicates things and I would like to avoid it.
Is it possible to do this without saving the file locally and sending a url where the file is located?
Browsers don't (yet) support JSON serialization of forms, so AFAIK it's not really possible to send JSON to backend using pure forms.
I have two solutions that will not require saving file on the server:
1) Simple solution would be to generate an invisible form with JavaScript, create hidden input of name json and populate it with JSON content to send to the server. On the server side, you would read the form data and parse JSON that is stored in the data. Then you just generate the file and send the file in response. The browser should trigger download dialog.
var form = document.createElement('form');
form.method = 'post';
form.action = 'url';
var input = document.createElement('input');
input.type = 'hidden';
textarea.name = 'json';
textarea.value = JSON.stringify(your_json);
form.appendChild(input);
document.body.appendChild(form);
form.submit();
form.parentNode.removeChild(form);
2) Second option uses ajax to send data to the server. The browsers need to support several APIs, though.
You do your JSON request as usual and the server should respond with header Content-Type: here-the-MIME-type-of-your-file and with the file contents in response body.
The code on client side should look like:
var json = JSON.stringify({here: ['your', 'json', 'to', 'send', 'to', 'server']});
var xhr = new XMLHttpRequest();
xhr.open('POST', '/your/api/url', true);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.responseType = 'arraybuffer';
xhr.addEventListener('load', function () {
var blob = new Blob([this.response], { // reading response, not responseText
type: this.getResponseHeader('Content-Type')
});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'file_name.txt'; // set proper extension
document.body.appendChild(a); // it needs to be added to the document in order to work
a.click();
a.parentNode.removeChild(a);
});
xhr.send(json);
Also, the created URL objects should be revoked at some point, otherwise they will exist until the page reloads. But I think they cannot be revoked before the user downloads the file. So it's one task still to do with the above code.
I am creating a web portal where end user will upload a csv file and I will do some manipulation on that file on the server side (python). There is some latency and lag on the server side so I dont want to send the message from server to client regarding the bad format of uploaded file. Is there any way to do heavy lifting on client side may be using js or jquery to check if the uploaded file is "comma" separated or not etc etc?
I know we can do "accept=.csv" in the html so that file extension has csv format but how to do with contents to be sure.
Accessing local files from Javascript is only possible by using the File API (https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications) - by using this you might be able to check the content whether it matches your expectations or not.
Here's some bits of code I used to display a preview image clientside when a file is selected. You should be able to use this as a starting point to do something else with the file data. Determining whether its csv is up to you.
Obvious caveat:
You still have to check server side. Anyone can modify your clientside javascript to pretend a bad file is good.
Another caveat:
I'm pretty sure that you can have escaped comma characters in a valid csv file. I think the escape character might be different across some implementations too...
// Fired when the user chooses a file in the OS dialog box
// They will have clicked <input id="fileId" type="file">
document.getElementById('fileId').onchange = function (evt) {
if(!evt.target.files || evt.target.files.length === 0){
console.log('No files selected');
return;
}
var uploadTitle = evt2.target.files[0].name;
var uploadSize = evt2.target.files[0].size;
var uploadType = evt2.target.files[0].type;
// To manipulate the file you set a callback for the whole contents:
var FR = new FileReader();
// I've only used this readAsDataURL which will encode the file like data:image/gif;base64,R0lGODl...
// I'm sure there's a similar call for plaintext
FR.readAsDataURL($('#file')[0].files[0]);
FR.onload = function(evt2){
var evtData = {
filesEvent: evt,
}
var uploadData = evt2.result
console.log(uploadTitle, uploadSize, uploadType, uploadData);
}
}
I'm creating a mobile app, and I want user to enter some details in text fields, and the results of those text fields I'm storing in a variable. At the end, I have a variable which consists of a large string. Then I want to be able to create a file, with a custom type, and store the value of that variable inside this file. Simply the file should consists of that text. So it will be a text file, only I will specify the extension. Then I will send that file to a server.
You can create a Blob for this, but it won't be "saved" to the client's device. The Blob can then be submitted to the server using an XMLHttpRequest
// bytes , mime
var b = new Blob(['text data'], 'text/plain');
// make it easy to submit or just submit it directly
var fd = new FormData();
fd.append('fileParam', b, 'file_name.txt');
// assuming XMLHttpRequest xhr
xhr.send(fd);
If FormData is not available for the device, then you can send the blob directly. Adding a FormData makes the server side easier as it is the same as if you submitted a <form> with some <input>.
I currently have a django formset with dynamic number of forms. Each form has a file field.
While this works, I need a way to allow multiple files to be selected at once. I can do that with input type='file' multiple='multiple' and I can read file data using FileReader. But how can I pass these files to django formset instead of form-0-file, form-1-file etc?
I can think of one way - replace FileField with TextField, and pass around the base64 encoded file as text, but I'm not sure if it's a good solution.
Just use multiple attribute and use FILES to get all of uploaded files.
base64 encoding maybe not help
Using multiple='multiple' is not related to formset or single form. It will work natively with django. So that if you plan to have single form instead of formset, just put multiple attribute and then access request.FILES to get all of uploaded files.
You should store the Images as Files,(Here are some good answers to do that),
I already tried to store images of that way but it have a lot of problems:
Every time you go to that page, it will start loading the image again, and the people don't want to load the same image every time.
It will use a lot of bandwidth.
If you are using a free web hosting service, will spend all you your bandwidth in a couple of hours, or when you store 50 images, so that mean that your site will be out the whole month, even the services that provide unlimited hosting and bandwidth, inforce a monthly bandwidth.
I recently had a problem where I had to implement a solution where a user can upload a document, stream that to the server, and without storing in on the server, post the stream to a SOAP server.
The way I implemented it, is as follows:
I wanted to upload the file via AJAX in order for me to show the progress of the upload.
This is my solution (Please note this only catered for one file at a time - but it might be a starting point.)
JavaScript:
First declare an object for the FormData - This will be used to send any additional info along with the files:
var formData = new FormData();
Secondly append all the data you would like to send to the server:
formData.append("documentDescription", $("#documentDescription textarea").val());
formData.append("afile", file.files[0]);
Now create a new instance of XMLHttpRequest:
var xhr = new XMLHttpRequest();
This is the rest of the code that got everything working:
xhr.open("POST", "UploadDocumentURL", true);
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;
$('.progress .bar').css('width', percentComplete + '%').attr('aria-valuenow', percentComplete);
}
}
xhr.onload = function() {
if (this.status == 200) {
var resp = JSON.parse(this.response);
if (resp.type === "error") {
notify.add(resp.type, "Error", resp.message, 3000, true);
} else {
notify.add(resp.type, "Success", resp.message, 3000);
}
}
;
};
xhr.send(formData);
PHP
$documentName = $_POST["documentDescription"];
$fileName = $_FILES['afile']['name'];
$fileType = $_FILES['afile']['type'];
$ext = pathinfo($fileName, PATHINFO_EXTENSION);
$fileName = pathinfo($fileName, PATHINFO_FILENAME);
$fileContent = file_get_contents($_FILES['afile']['tmp_name']);
You will now have the Binary data on the server.
You should be able to make this work for multiple files by looping through the file.files[0] in JavaScript.
Hope you can apply this to your problem.