How in bootstrap-vue convert FileReader to blob and upload to server? - blob

In #vue/cli 4.1.1 app I use bootstrap-vue and b-form-file conponent for images uploading
https://bootstrap-vue.js.org/docs/components/form-file/#multiple-files
with definition :
<b-form-file
id="upload_ad_image"
v-model="new_upload_ad_image"
:state="Boolean(new_upload_ad_image)"
placeholder="Choose a file or drop it here..."
drop-placeholder="Drop file here..."
accept="image/jpeg, image/png, image/gif"
></b-form-file>
<div ref="uploaded_img_preview" id="uploaded_img_preview" class="m-2" >Uploaded image preview :</div>
I found snippet https://codepen.io/Tenderfeel/pen/rgqWXR
and using it I show selected file on my form for preview.
Next I need to upload it on the server. I have an expierence of uploading image as blog using code like :
fetch(this.taskRow.imageFile.blob).then(function (response) {
if (response.ok) {
return response.blob().then(function (imageBlob) {
let imageUploadData = new FormData()
imageUploadData.append('id', self.taskRow.id)
imageUploadData.append('image', imageBlob)
imageUploadData.append('image_filename', self.taskRow.imageFile.name)
But I need to convert uploading image to blob. I use method when image is selected:
But got error : Error in callback for watcher "new_upload_ad_image": "InvalidStateError: Failed to execute 'readAsDataURL' on 'FileReader': The object is already busy reading Blobs
watch: {
new_upload_ad_image(val) {
if (!val) return;
if (this.previewImg) {
this.previewImg.remove();
}
const img = document.createElement("img");
img.classList.add("obj");
img.file = this.new_upload_ad_image;
console.log('img.file::')
console.log(img.file)
this.previewImg = img;
console.log('this.$refs.uploaded_img_preview::')
console.log(this.$refs.uploaded_img_preview)
console.log('img::')
console.log(img)
this.$refs.uploaded_img_preview.appendChild(img);
const fileReader = new FileReader();
fileReader.onload = (e) => {
this.previewImg.src = e.target.result;
};
fileReader.readAsDataURL(this.new_upload_ad_image);
console.log('fileReader::')
console.log(fileReader)
let blobObj= fileReader.readAsDataURL(img.file) // RAISE ERROR :
console.log('blobObj::')
console.log(blobObj)
}
},
What I see in the console : https://imgur.com/a/2EZxq9C
How to get blob and upload it on server?
MODIFIED BLOCK :
having file input with id="upload_ad_image" defined :
<b-form-file
id="upload_ad_image"
v-model="new_upload_ad_image"
:state="Boolean(new_upload_ad_image)"
placeholder="Choose a file or drop it here..."
drop-placeholder="Drop file here..."
accept="image/jpeg, image/png, image/gif"
></b-form-file>
I run fetch and see that image blob is invalid and file is created, but it is invalid
I have :
var self = this
const upload_ad_image = document.getElementById('upload_ad_image')
console.log('upload_ad_image::')
console.log(upload_ad_image)
console.log('upload_ad_image.files::')
console.log(upload_ad_image.files[0])
if (typeof upload_ad_image.files[0] == 'undefined') {
self.showPopupMessage('Ad image upload', 'Invalid image !', 'warn')
return
}
fetch(upload_ad_image.files[0].blob).then(function (response) {
if (response.ok) {
return response.blob().then(function (imageBlob) {
console.log('imageBlob::')
console.log(imageBlob) // Looks like this var has invalid content(printscreen below)!
let imageUploadData = new FormData()
imageUploadData.append('ad_id', self.editableAd.id)
imageUploadData.append('main', self.new_upload_ad_image_main)
imageUploadData.append('info', self.new_upload_ad_image_info)
imageUploadData.append('image', imageBlob)
imageUploadData.append('image_filename', upload_ad_image.files[0].name)
I see in console : https://imgur.com/a/4ees55C
What is wrong and how it can be fixed ?
"bootstrap-vue": "^2.3.0",
"vue": "^2.6.11",
Thanks!

File objects do inherit from the Blob interface.
All you can do with a Blob, you can also do it with a File, so in your code you can directly append this.new_upload_ad_image to your FormData.
const inp = document.getElementById('inp');
inp.onchange = (evt) => {
const formData = new FormData();
formData.append( 'my-file', inp.files[0], 'file.ext' );
// check it's correctly in the FormData
console.log( [...formData.entries()] );
};
<input type="file" id="inp">

Related

How to convert image from file input to base64 url in vue?

I have tried to convert an image from file input in vue, I'm not so sure I did it in the proper way.
What I want to achieve is to get the Image url, assign it to a data variable and push it into my mongoose DB
That's what I tried based on a guide I read:
Input:
<div class="singleInput50">
<span>Personal Image:</span>
<input type="file" #change="handleImage" accept="image/*">
</div>
HandleImage:
handleImage(e) {
const selectedImage = e.target.files[0];
this.createBase64Image(selectedImage);
},
createBase64Image:
createBase64Image(fileObject) {
const reader = new FileReader();
reader.onload = (e) => {
this.userObject.imgPersonal = e.target.result;
};
reader.readAsBinaryString(fileObject)
console.log("file object", fileObject);
}
ImgPersonal value after the functions has been executed:
imgPersonal:"ÿØÿàJFIFÿÛC\n \n \n$ &%# #"(-90(*6+"#2D26;=###&0FKE>J9?#=ÿÛC =)#)==================================================ÿÀ"ÿÄ \nÿĵ}!1AQa"q2¡#B±ÁRÑð$3br \n%&'()*456789:CDEFGH
I have tried also with readAsDataURL(), seems like the same outcome
Any suggestions?
I'm using this function to convert files to base64. Works fine for me:
export default function (blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onerror = reject
reader.onload = () => {
resolve(reader.result)
}
reader.readAsDataURL(blob)
})
}

How to preview files before uploaded to server by using file-upload component of vue.js & element-ui?

I'm using vue.js & element-ui to upload files and preview files. I want to preview file(.pdf/.docx/.jpg...) before uploaded to server.
<el-upload
ref="uploadFile"
:on-change="onUploadChange"
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:file-list="fileList"
:http-request="handleUpload"
:data="extendData"
:auto-upload="false"
class="upload-demo"
drag
action="uploadUrl"
multiple>
<i class="el-icon-upload"/>
<div class="el-upload__text">drag here, or <em>click to upload</em></div>
</el-upload>
Only the on-change function can get the content of the file, while the on-preview function only get the meta message. How to get the file content and preview that before which is uploaded to server?
It's not the meta, it's the file. So you need to use a FileReader on the file:
handlePreview(file) {
const reader = new FileReader()
reader.onload = e => console.log(e.target.result) // here is the result you can work with.
reader.readAsText(file)
}
I am also using Element-UI upload box, the following code allow user to import a JSON file to Vue, and preview its content in a new window when clicking the file name. The file is read and stored as object in data during on-change, then
Vue component:
<el-upload class="upload-box" drag action="" :auto-upload="false" :on-change="handleImport" :on-preview="handlePreview" :limit="1" :on-exceed="handleExceed">
<i class="el-icon-upload"></i>
<div class="el-upload__text">Drop file here or <em>click to upload</em></div>
<div class="el-upload__tip" slot="tip">Single JSON file with size less than 500kb</div>
</el-upload>
Script:
export default {
data() {
return {
uploadFile: null,
fileContent: null,
}
},
methods: {
handleImport(file) {
this.uploadFile = file
let reader = new FileReader()
reader.readAsText(this.uploadFile.raw)
reader.onload = async (e) => {
try {
this.fileContent = JSON.parse(e.target.result)
} catch (err) {
console.log(`Load JSON file error: ${err.message}`)
}
}
},
handlePreview() {
let myWindow = window.open();
myWindow.document.write(JSON.stringify(this.fileContent));
myWindow.document.close();
},
handleExceed(files, fileList) {
this.$message.warning(`The limit is 1, you selected ${files.length + fileList.length} totally, please first remove the unwanted file`);
},
},
}

Vuejs. I can't transfer data to an Object

I would like to catch uploaded file in FilePond. but the base64 of the file isn't transfered to my object. Any solutions?
In template
<FilePond
v-on:addfile="catch"
/>
In Data
data:function() {
return {
image:'',
}}
in Method
catch: function(fieldName, file) {
console.log('#', file.file) // The Blop format file appears in console
const reader = new FileReader(); //convert to base64
reader.readAsDataURL(file.file);
reader.onloadend = function() {
console.log('yy',reader.result); // Base64 image appears in console
(600000 carac)
this.image= reader.result ; // HERE, the object still blank
} },
Error in console :
Uncaught TypeError: Cannot set property 'image' of undefined
at FileReader.reader.onloadend
this keyword is shadowed by the onloadend function, save this before defining the function and then reference it inside:
methods: {
catch: function(fieldName, file) {
// ...
var ref = this
reader.onloadend = function() {
ref.image= reader.result // use ref here
}
// ...
}
}

VueJS file upload not accepting file

I'm working on a file upload image preview with VueJS and I'm having an issue where...
1. - file get uploaded by user
2. - preview comes up beside the input field
3. - input field now says there is no image uploaded though there is the preview.
here is the html:
<input type='file' accept='image/*' #change="onChange" name='file' />
<img width='200' :src="uploadPreview" alt='preview' />
here is my vueJs code:
data: function() { return {
uploadPreview : "",
}
},
methods : {
onChange(e) {
if (! e.target.files.length) return;
let file = e.target.files[0];
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = e => {
this.uploadPreview = e.target.result; // if this line is commented out or just not present, the upload will work but the preview won't show since uploadPreview does not have a value set.
};
},
}
there's something with that line that I commented in the code there.
this.uploadPreview = e.target.result;
if this line is commented out or just not present, the upload will work but the preview won't show since uploadPreview does not have a value set.
Why is this not working? Why does the input field value for the file reset after simply setting uploadPreview to some binary image data??? Banging my head on this table once more.
I suggest you debugging points. Try and let me know.
data: function() { return {
uploadPreview : "ABCD",
}
},
methods : {
onChange(e) {
if (! e.target.files.length) return;
let file = e.target.files[0];
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = e => {
console.log("FIRST SEE WHAT'S INSIDE THE RESULTS",e.target.result);
console.log("SECOND MAKE SURE YOU CAN ACCESS",this.uploadPreview) // this should print ABCD
this.uploadPreview = e.target.result; // if this line is commented out or just not present, the upload will work but the preview won't show since uploadPreview does not have a value set.
};
},
}
and finally
<img width='200' :src="uploadPreview" :alt='uploadPreview' />
(alt should equals to image data)

How to get uploaded image in serverside using Ember.js

I'm new to Ember.js and I'm stuck with a problem I need to save the uploaded image in db but I dont know how to do that I wrote code for upload the image but i'm stuck with passing it to the server my current code is given below
App.js
App = Ember.Application.create();
App.PreviewImageView = Ember.View.extend({
attributeBindings: ['name', 'width', 'height', 'src'],
tagName: 'img',
viewName: 'previewImageView',
printme: function () {
console.log('in previewImageView');
}
});
App.FileField= Ember.TextField.extend({
type: 'file',
attributeBindings: ['name'],
change: function (evt) {
var input = evt.target;
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
this.$().parent(':eq(0)').children('img:eq(0)').attr('src', e.target.result);
var view = that.getPath('parentView.previewImageView');
view.set('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
});
html
<script type="text/x-handlebars">
{{view App.FileField name="logo_image" contentBinding="content"}}
{{view App.PreviewImageView width="200" height="100" }}
</script>
I think you can mix some traditional MVC methods to solve your problem. from your current code I can assume that showing a preview of the image is completed so to get that file in server side just use the following code in your html
#using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" {{view Wizard.FileField contentBinding="content"}} />
<input type="submit" id="btnUpload" value="Upload" />
}
and In you controller method you can access the file like this
public ActionResult FileUpload(HttpPostedFileBase file)
{
// Do what you want
}
To save the image in db you have to convert it into bytes (sql server 2008 support image now but db like postgresql still need image as bytes) to do that use the following method
MemoryStream target = new MemoryStream();
file.InputStream.CopyTo(target);
byte[] bytes= target.ToArray();
return View();
Assuming you are using ember-data, you can create a model to represent the image and then create/save from the reader's onload callback. For example:
App.LogoImage = DS.Model.extend({
id: DS.attr('number'),
attachment: DS.attr('string')
});
//in App.FileField...
reader.onload = function (e) {
this.$().parent(':eq(0)').children('img:eq(0)').attr('src', e.target.result);
var view = that.getPath('parentView.previewImageView');
view.set('src', e.target.result);
var file = e.srcElement.result;
var logo = App.LogoImage.createRecord({ attachment: file });
logo.save();
}