Getting octet-stream instead of image in node js - node.js

In my front-end I use angular6 and I have this form where you can choose an image either by dropping a file in a div or clicking the div to open a file picker.
The form is
<form [formGroup]="imageUpload" (ngSubmit)="imageUploadSubmitted($event.target)" >
<div id="imageDrop" (click)='imageInput.click()' (drop)="drop($event)" (dragover)="allowDrop($event)" #imageDrop></div>
<input type="file" (change)='imageChange($event)' #imageInput id="imageInput" name = 'imageInput' accept=".png, .jpg, .jpeg, .gif" formControlName="imageInput" required >
<button type="submit" >Submit</button>
</form>
This is the typescript
selectedFile:File=null;
allowDrop(e) {
e.preventDefault();
}
drop(e) {
e.preventDefault();
this.imageUpload.controls.imageInput.reset();
this.selectedFile = e.dataTransfer.files[0];
let input = this.imageUpload.controls.imageInput as any;
input.value = e.dataTransfer.files[0];
}
imageChange(e){
this.selectedFile = e.target.files[0];
}
So, when dropping an image, get it from the event and put it in the file input. When the form is submitted, send the form data to a service for posting. The console.log shows a File object (__proto__ : File) whether you picked an image from the file picker, or dropped one in the div.
imageUploadSubmitted(form){
console.log('imageInput value - ', this.imageUpload.controls.imageInput.value);
this.mapcmsService.uploadImage(form).subscribe((data) =>{
if(data.success){ alert('all good'); }
else{ alert('error'); }
})
}
The service grabs the form controls and builds a FormData object to send in node.
uploadImage(data){
let formData = new FormData(data);
let headers = new Headers();
headers.append('Authorization',this.userToken);
return this.http.post('http://localhost:3000/user/upload/image', formData ,{headers:headers} ).pipe(map(res => res.json()));
}
In node I use formidable to get the file and save it. This is for testing.
var form = new formidable.IncomingForm();
form.parse(req);
form.on('file', function (name, file){
console.log('file' , file);
});
The problem is that if I have chose an image via the file picker, I get a file of type image/jpeg , a name a path and a size.
If I chose an image by drag and drop, I get a file of type application/octet-stream. This has no name and no size.
I would like to get image/jpeg in both cases. I am confused, is this a node or angular issue? How can I fix this ?
Thanks
angular 6 , node 8.11.1, formidable 1.2.1

The issue is that the assignment in the drop event does not actually set the value of the input because file inputs are not supported by Angular reactive forms. I am talking about this lines:
let input = this.imageUpload.controls.imageInput as any;
input.value = e.dataTransfer.files[0];
So when you drop in your case you are not actually sending the file to the server at all. That is why the data you get is wrong. Here are also links to two other stack overflow questions about reactive forms and file upload where there is more information regarding this issue.
How to include a file upload control in an Angular2 reactive form?
Using reactive form validation with input type=“file” for an Angular app
There are two possible solutions to workaround this issue. The first is that you get the ElementRef of the file input by using the ViewChild query. And then assign the files to the native html element directly. The good thing with this approach is that you will see the dropped file name also in the file input. The downside is that this might not work in all browsers. The official documentation on MDN says that it works in modern browsers but for me it did work in Chrome and not in Edge.
Here is a sample of the code:
#ViewChild('imageInput') private imageInput: ElementRef;
public drop(e: DragEvent) {
e.preventDefault();
this.imageUpload.controls.imageInput.reset();
this.selectedFile = e.dataTransfer.files[0];
this.imageInput.nativeElement.files = e.dataTransfer.files;
}
The other approach is that you build the FormData object yourself by adding the selected file yourself in code before sending it to the server. This should work anywhere without issues. Here is a sample code:
let formData = new FormData();
formData.append('imageInput', this.selectedFile);
I have created also a StackBlitz example where you can see all the code.

Related

KendoReact upload - passing file Id to React after saving file

I'm a bit stuck with the kendo react upload control.
I need to customise the rendering of the kendo react upload control.
After the user upload the file, I want to save the file in database. Then I need to pass the database Id back to the client because if the user then wants to remove the file I also need to clear the database.
To give you an idea this is what I would like to achieve.
https://stackblitz.com/edit/react-ghna5h
(When you start stackblitz open file app/main.jsx)
Is it possible?
Thanks for your help
I solved this particular issue using a combination of the onStatusChange and onBeforeRemove events. The server's 'save' endpoint returns an id (responseUID) that can be accessed through the onChange event's response object. I set this id on the 'file' object. Then when you're removing the file I pass the responseUID along in the additionalData field which gets put into the POST body.
const onStatusChange = (e) => {
if (e.response) {
const fileId = e.response.response.responseUID;
// This does not deal with multiple or batch uploads.
e.affectedFiles[0].responseUID = fileId;
}
};
const onBeforeRemove = (e) => {
e.additionalData.responseUID = e.files[0].responseUID;
};
return (
<Upload
batch={false}
defaultFiles={[]}
withCredentials={false}
saveUrl="https://localhost/upload/save"
removeUrl="https://localhost/upload/remove"
onStatusChange={onStatusChange}
onBeforeRemove={onBeforeRemove}
/>
);

what is the difference between readFileSync and readAsDataURL?

NOTE: this is NOT a production application. It is a small app that I am making to explore the capabilities of selecting, opening, saving and reading an image from a DB.
I do not know what method I should call to get the correct Buffer data to store image in mongodb. ( I am aware that mongoDB has a 16mb limit on documents )
In my app, I want the user to be able to select an image from a file on their pc, give the user a preview of the image, then when the user hits submit (not shown here) save the image into mongodb
I know when the user clicks the "choose file" button I can get the file like this:
const file = event.target.files[0]
if (!file) {
// user has hit the cancel button
return;
}
//console.log(file);
I can get information about the file:
console.log(file.type);
console.log(file.size);
and here is how the image is read:
let fr = new FileReader();
fr.readAsDataURL(file);
fr.onload = (e) =>{
this.productImageAdd(e.target.result);
}
This is how the image is stored in the (react) component state
productImageAdd = (file) => {
let temp = this.state["filesArray"] || [];
temp.push(file);
this.setState({"filesArray": temp});
}
Here is the state of my component
this.state = {
filesArray: [],
};
In another component, I get a listing of all the images and then map them to an item for display:
return filesArray.map((file, index) => (
<FileDropZoneItem key={index} id={index} file={file} />
));
In FileDropZoneItem, this is how images are "previewed":
return (
<li className="flex-item ">
<img src={file} width="200" height="200"/>
</li>
);
I saw this stackoverflow question and I am moving towards that to store the image in MongoDB:
Store an image in MongoDB using Node.js/Express and Mongoose
In that post, their schema is like this:
var schema = new Schema({
img: { data: Buffer, contentType: String }
});
And they store the image like this:
var A = mongoose.model('A', schema);
var a = new A;
a.img.data = fs.readFileSync(imgPath);
a.img.contentType = 'image/png';
but I don't really know the difference between fs.readFileSync and fr.readAsDataURL.
Will storing to mongodb work using fr.readAsDataURL or do I need fs.readFileSync ?
I also saw: Difference between readAsBinaryString() and readAsDataURL() in HTML5 FileReader API
From the MongoDB manual GridFS
GridFS uses two collections to store files. One collection stores the file chunks, and the other stores file metadata. The section GridFS Collections describes each collection in detail.
For reference you can read Storing images in MongoDB
readAsDataURL permits to store the images inside the JSON document encoded as base64 characters. Given the size of the Products pictures 200px x 200px seems the best option for your hello world app.
readFileSync can have blocking issues in the server like Nodejs for image handling behavior and reads the binary file to store it as Binary Data.
IMO the best solution is to not overload mongoDB and Nodejs with the image handling and store only an URL to the image in the mongoDB document leaving the image serving process to a proxy like nginx.
The Gridfs option depends on the driver used. Following is Gridfs use in Nodejs that uses its own reader:
fs.createReadStream('./meistersinger.mp3').
pipe(bucket.openUploadStream('meistersinger.mp3')).

How to upload file asynchronously in grails 3

I am new to grails framework and I am stuck with the following problem:
I want to upload project with file and some details like title,description and I have very big stl 3d file. While file upload takes time i want user to go on next page and fill the project rest details like , title description etc.
I am not able to figure out that how i will do this ..I had look in grails aynch programming but i could not figure out how to implement that.
I will really appreciate if someone guides on this
I worked on a form a while back that includes file uploads, which I wanted to be done asynchronously. It took lots of Googling, and unfortunately I do not remember any of the references I used, but here is what I ended up doing.
I included an onchange attribute on the file input that, when a file was selected, would call a javascript function to validate and upload the file asynchronously.
The file input:
<input type="file" name="uploadMedical" id="uploadMedical" onchange="validateAndUpload(this, $(this));" accept=".pdf,.jpg,.jpeg" multiple>
The JavaScript
(I did my best to strip out code that is not relevant to your question while still leaving enough to help solve your problem):
function validateAndUpload(input, documentInput){
var uploadForm = $("#uploadForm");
// Stop the browser from submitting the form.
uploadForm.submit(function(event) {
event.preventDefault();
});
// Get the selected files from the input.
var files = input.files;
// Create a new FormData object.
var formData = new FormData();
// Loop through each of the selected files.
for (var ii = 0; ii < files.length; ii++) {
var file = files[ii];
// Add the file to the request.
formData.append('supportingDocumentation', file, file.name);
}
//Include ID of record to associate this upload with
formData.append('id', getAppealId());
// Submit the form using AJAX.
$.ajax({
type: 'POST',
dataType : "html",
url: url_str,
data: formData,
processData: false,
contentType: false,
beforeSend:function(){
//indicate that the file is uploading
},
success:function(htmlData){
//display the new list of files on the page
},
error:function(ee){
//indicate that the upload failed
},
complete:function(){
//reset the file input so more files can be uploaded
}
})
}

How add file into p:fileUpload [duplicate]

How can I set the value of this?
<input type="file" />
You cannot set it to a client side disk file system path, due to security reasons.
Imagine:
<form name="foo" method="post" enctype="multipart/form-data">
<input type="file" value="c:/passwords.txt">
</form>
<script>document.foo.submit();</script>
You don't want the websites you visit to be able to do this, do you? =)
You can only set it to a publicly accessible web resource as seen in this answer, but this is clearly not the same as a client side disk file system path and it's therefore useless in that context.
You can't.
The only way to set the value of a file input is by the user to select a file.
This is done for security reasons. Otherwise you would be able to create a JavaScript that automatically uploads a specific file from the client's computer.
Not an answer to your question (which others have answered), but if you want to have some edit functionality of an uploaded file field, what you probably want to do is:
show the current value of this field by just printing the filename or URL, a clickable link to download it, or if it's an image: just show it, possibly as thumbnail
the <input> tag to upload a new file
a checkbox that, when checked, deletes the currently uploaded file. note that there's no way to upload an 'empty' file, so you need something like this to clear out the field's value
You can't. And it's a security measure. Imagine if someone writes JS that sets file input value to some sensitive data file?
I have write full example for load URL to input file, and preview
you can check here
1
https://vulieumang.github.io/vuhocjs/file2input-input2file/
in short you can use this function
function loadURLToInputFiled(url){
getImgURL(url, (imgBlob)=>{
// Load img blob to input
// WIP: UTF8 character error
let fileName = 'hasFilename.jpg'
let file = new File([imgBlob], fileName,{type:"image/jpeg", lastModified:new Date().getTime()}, 'utf-8');
let container = new DataTransfer();
container.items.add(file);
document.querySelector('#file_input').files = container.files;
})
}
// xmlHTTP return blob respond
function getImgURL(url, callback){
var xhr = new XMLHttpRequest();
xhr.onload = function() {
callback(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
As everyone else here has stated: You cannot upload just any file automatically with JavaScript.
HOWEVER! If you have access to the information you want to send in your code (i.e., not C:\passwords.txt), then you can upload it as a blob-type, and then treat it as a file.
What the server will end up seeing will be indistinguishable from someone actually setting the value of <input type="file" />. The trick, ultimately, is to begin a new XMLHttpRequest() with the server...
function uploadFile (data) {
// define data and connections
var blob = new Blob([JSON.stringify(data)]);
var url = URL.createObjectURL(blob);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'myForm.php', true);
// define new form
var formData = new FormData();
formData.append('someUploadIdentifier', blob, 'someFileName.json');
// action after uploading happens
xhr.onload = function(e) {
console.log("File uploading completed!");
};
// do the uploading
console.log("File uploading started!");
xhr.send(formData);
}
// This data/text below is local to the JS script, so we are allowed to send it!
uploadFile({'hello!':'how are you?'});
So, what could you possibly use this for? I use it for uploading HTML5 canvas elements as jpg's. This saves the user the trouble of having to open a file input element, only to select the local, cached image that they just resized, modified, etc.. But it should work for any file type.
the subject is very old but I think someone can need this answer!
<input type="file" />
<script>
// Get a reference to our file input
const fileInput = document.querySelector('input[type="file"]');
// Create a new File object
const myFile = new File(['Hello World!'], 'myFile.txt', {
type: 'text/plain',
lastModified: new Date(),
});
// Now let's create a DataTransfer to get a FileList
const dataTransfer = new DataTransfer();
dataTransfer.items.add(myFile);
fileInput.files = dataTransfer.files;
</script>
You need to create a DataTransfer and set the .files property of the input.
const dataTransfer = new DataTransfer();
dataTransfer.items.add(myFile);//your file(s) reference(s)
document.getElementById('input_field').files = dataTransfer.files;
Define in html:
<input type="hidden" name="image" id="image"/>
In JS:
ajax.jsonRpc("/consulta/dni", 'call', {'document_number': document_number})
.then(function (data) {
if (data.error){
...;
}
else {
$('#image').val(data.image);
}
})
After:
<input type="hidden" name="image" id="image" value="/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8U..."/>
<button type="submit">Submit</button>
Actually we can do it.
we can set the file value default by using webbrowser control in c# using FormToMultipartPostData Library.We have to download and include this Library in our project. Webbrowser enables the user to navigate Web pages inside form.
Once the web page loaded , the script inside the webBrowser1_DocumentCompleted will be executed.
So,
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
FormToMultipartPostData postData =
new FormToMultipartPostData(webBrowser1, form);
postData.SetFile("fileField", #"C:\windows\win.ini");
postData.Submit();
}
Refer the below link for downloading and complete reference.
https://www.codeproject.com/Articles/28917/Setting-a-file-to-upload-inside-the-WebBrowser-com

How to upload a file (attachment) from the browser?

I don't get attachment upload for the browser to work.
Some hints are here, others there. The docs are quite good but I'm unable to translate that to a AJAX upload.
I'm looking for a super simple HTML/JavaScript example (with or w/o jQuery) of how to upload a file from (relatively modern) browser to the db without making use of jquery.couch.app.js wrapper or stuff. The simpler the besser.
Any help appreciated.
Alright, here's your pure JavaScript file upload implementation.
The basic algorithm is like this:
Get the file from the file input element
Get the file name and type off the file object
Get the latest document revision of the document you want to attach the file to
Attach the file to document using the fetched revision
The HTML part basically consists of a simple form with two elements, an input of type file and a button of type submit.
<form action="/" method="post" name="upload">
<input type="file" name="file" />
<button type="submit" name="submit">Upload</button>
</form>
Now to the JavaScript part.
window.onload = function() {
var app = function() {
var baseUrl = 'http://127.0.0.1:5984/playground/';
var fileInput = document.forms['upload'].elements['file'];
document.forms['upload'].onsubmit = function() {
uploadFile('foo', fileInput.files[0]);
return false;
};
var uploadFile = function(docName, file) {
var name = encodeURIComponent(file.name),
type = file.type,
fileReader = new FileReader(),
getRequest = new XMLHttpRequest(),
putRequest = new XMLHttpRequest();
getRequest.open('GET', baseUrl + encodeURIComponent(docName),
true);
getRequest.send();
getRequest.onreadystatechange = function(response) {
if (getRequest.readyState == 4 && getRequest.status == 200) {
var doc = JSON.parse(getRequest.responseText);
putRequest.open('PUT', baseUrl +
encodeURIComponent(docName) + '/' +
name + '?rev=' + doc._rev, true);
putRequest.setRequestHeader('Content-Type', type);
fileReader.readAsArrayBuffer(file);
fileReader.onload = function (readerEvent) {
putRequest.send(readerEvent.target.result);
};
putRequest.onreadystatechange = function(response) {
if (putRequest.readyState == 4) {
console.log(putRequest);
}
};
}
};
};
};
app();
};
Basically, I intercept the submit event of the form by binding my own function to the form's onsubmit event and returning false.
In that event handler I call my main function with two parameters. The first one being the document name and the second one being the file to upload.
In my uploadFile() function I set the file name, file type and grab some instances. The first HTTP request is a GET request to obtain the current revision of the document. If that request succeeds I prepare the PUT request (the actual upload request) by setting the previously obtained revision, the proper content type and then I convert the file to an ArrayBuffer. Once that's done I just send the HTTP request I've just prepared and then I relax.
The standalone attachment upload scheme looks like this:
PUT host/database/document/filename?revision=latest-revision
Of course using the proper content type in the HTTP request header.
Note: I'm well aware that I'm not making use of defensive programming here at all, I did that deliberately for brevity.

Resources