I'm creating an upload VueJS component and I've this portion to display the images in the images object:
<div class="row">
<figure class="col-md-3" v-for="image in images">
<img :src="'/'+image.image" :alt="image.description+'-'+image.image" class="img-responsive"
style="width:100%;">
</figure>
</div>
I want to know if there's a way yo image the images after every successful upload and to get the newly uploaded images.
Here's the the method I'm using to submit the images :
props: ['data'],
data() {
return {
files: [],
slug: this.data.slug,
id: this.data.part.id,
images : this.data.part.images
}
},
methods: {
submitFiles() {
let formData = new FormData();
for (let i = 0; i < this.files.length; i++) {
let file = this.files[i];
formData.append('files[' + i + ']', file);
}
axios.post('/dashboard/galleries/',
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(function () {
console.log('SUCCESS!!');
})
.catch(function () {
console.log('FAILURE!!');
});
}
Thanks to everyone for helping.
what you can do is after uploading your files is to return a response containing your images urls like so:
return response()->json(['images' => $images]);
and then in your .then block you can assign the response to your images piece of data like so:
axios.post('/dashboard/galleries/',
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(function (res) {
this.images = res.data.images;
})
update
since the data is going to change when we get the response we will need to use watch like so:
props: ...,
methods: ...,
watch: {
images: function(val) {
this.images = val;
}
}
use this https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL to display image from base64 string. There is a simple example.
Related
I have a GET request with axios and get a .png file back and want to show this inside my template. I can't use a path url, because the image is each time differently.
This is my fastapi route.
from io import BytesIO
from fastapi.responses import Response
#app.get("/image", response_class=Response)
def load_image():
...
buffer = BytesIO()
img.save(buffer, format="PNG")
return Response(content=buffer.getvalue(), media_type="image/png")
This is the vue component:
<script>
export default {
name: "Example",
data() {
return {
image: null;
};
},
methods: {
async loadImage() {
const url = "/image";
const response = await $axios.get(url, { responseType: "arraybuffer" });
if (response.status == 200) {
const base64string = btoa(String.fromCharCode(...new Uint8Array(response.data)));
console.log(base64string); // -> this is a empty string
this.image = 'data:image/png;base64,' + base64string;
}
},
mounted() {
this.loadImage();
},
};
</script>
<template>
<div>
<img :src="image" title="Image" />
</div>
</template>
You can...
get the data as a blob by passing { responseType: "blob" } to axios
convert the blob to base64 with FileReader (used blobToData function from https://stackoverflow.com/a/63372663/197546)
use the base64 data as the image src
example:
const app = Vue.createApp({
data() {
return {
imageSrc: null,
};
},
methods: {
async loadImage() {
const url =
"https://images.unsplash.com/photo-1664300067908-84e8beb52a8f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyNXx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60";
const response = await axios.get(url, { responseType: "blob" });
if (response.status == 200) {
const base64data = await blobToData(response.data);
this.imageSrc = base64data;
}
},
},
mounted() {
this.loadImage();
},
});
app.mount("app");
function blobToData(blob) {
return new Promise((resolve) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.readAsDataURL(blob)
})
}
<script src="https://unpkg.com/vue#next/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/axios#0.27.2/dist/axios.min.js"></script>
<app>
<img :src="imageSrc" v-if="imageSrc"/>
</app>
As Chris pointed out, you can also...
get the data as an array buffer by passing { responseType: "arraybuffer" } to axios
convert array to base64 data using btoa(String.fromCharCode(...new Uint8Array(response.data)))
build the src data by adding prepending the content type to the base64 data
example:
const app = Vue.createApp({
data() {
return {
imageSrc: null,
};
},
methods: {
async loadImage() {
const url =
"https://images.unsplash.com/photo-1664300067908-84e8beb52a8f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyNXx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60";
const response = await axios.get(url, { responseType: "arraybuffer" });
if (response.status == 200) {
const b64 = btoa(String.fromCharCode(...new Uint8Array(response.data)));
const imgData = "data:" + response.headers['content-type'] + ";base64," + b64;
this.imageSrc = imgData;
}
},
},
mounted() {
this.loadImage();
},
});
app.mount("app");
<script src="https://unpkg.com/vue#next/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/axios#0.27.2/dist/axios.min.js"></script>
<app>
<img :src="imageSrc" v-if="imageSrc"/>
</app>
I am trying to upload multiple images using vuejs and axios but on server side i am getting empty object. I added multipart/form-data in header but still empty object.
submitFiles() {
/*
Initialize the form data
*/
let formData = new FormData();
/*
Iteate over any file sent over appending the files
to the form data.
*/
for( var i = 0; i < this.files.length; i++ ){
let file = this.files[i];
console.log(file);
formData.append('files[' + i + ']', file);
}
/*`enter code here`
Make the request to the POST /file-drag-drop URL
*/
axios.post( '/fileupload',
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
},
}
).then(function(){
})
.catch(function(){
});
},
HTML:
<form method="post" action="#" id="" enctype="multipart/form-data">
<div class="form-group files text-center" ref="fileform">
<input type="file" multiple="multiple">
<span id='val'></span>
<a class="btn" #click="submitFiles()" id='button'>Upload Photo</a>
<h6>DRAG & DROP FILE HERE</h6>
</div>
My Server side code:
class FileSettingsController extends Controller
{
public function upload(Request $request){
return $request->all();
}
}
Output:
{files: [{}]}
files: [{}]
0: {}
Console.log() result:
File(2838972) {name: "540340.jpg", lastModified: 1525262356769, lastModifiedDate: Wed May 02 2018 17:29:16 GMT+0530 (India Standard Time), webkitRelativePath: "", size: 2838972, …}
You forgot to use $refs. Add ref to your input:
<input type="file" ref="file" multiple="multiple">
Next, access your files like this:
submitFiles() {
const formData = new FormData();
for (var i = 0; i < this.$refs.file.files.length; i++ ){
let file = this.$refs.file.files[i];
formData.append('files[' + i + ']', file);
}
axios.post('/fileupload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
}
).then(function(){
})
.catch(function(){
});
},
This should be works.
If anyone wondering, "How can I send also data with it", there you go:
formData.append('name[' + this.name + ']', name);
formData.getAll('files', 'name');
For Composition API this should work:
const files = ref([])
function save() {
let formData = new FormData()
for (let file of files.value) {
formData.append('files', file)
}
axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then((response) => {
})
}
i'm working in Laravel. i need to upload file with Vuejs. but it's not working. I add this code:
Blade (File upload):
<input class="form-control" type="file" >
Script Vuejs :
var app = new Vue({
el: '#app',
data: {
person: {
id: 0,
user_name:'',
position_id:'',
image:'',
},
},
methods: {
addPerson: function () {
axios.post('/addperson', this.person)
.then(response => {
console.log(response.data);
if (response.data.etat) {
this.person = {
id: 0,
user_name: response.data.etat.user_name,
position_name: response.data.etat.position_id,
image: response.data.etat.image
};
}
})
.catch(error => {
console.log('errors: ', error)
})
},
Controller:
public function addPerson(Request $request){
$person = new Person;
$person->user_name=$request->user_name;
$person->position_id=$request->position_id;
if($request->hasFile('photo')){
$person->image= $request->image->store('image');
}
$person->save();
return back()->with('success', 'New Position added successfully.');
My Axios post function is working without the image upload line code. I just don't know how to add the upload code.
Thank you if someone can help.
In your blade file
<input type="file" #change="onFileChange" name="id_image" id="id_image" class="inputFile">
In your vue.js file, under methods:
onFileChange(e) {
let files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
},
createImage(file) {
let reader = new FileReader();
reader.onload = (e) => {
this.person.image = e.target.result;
};
reader.readAsDataURL(file);
},
That should allow your axios code to upload the image. Note, that it uploads in base64, so if you need validators you will have to create a custom Validator for base64 images.
I struggled to find out how to do this, but I've now found a way. Hopefully this makes someones life easier(I have the uploadUserImage method in a mixin):
HTML:
<input type="file" #change="uploadImage($event)">
JS:
uploadImage (e) {
this.file = e.currentTarget.files[0]
let formData = new FormData()
formData.append('img', this.file)
this.uploadUserImage(formData)
}
uploadUserImage: function (formData) {
axios.post('http://snowdon-backend.local:8000/api/users/img', formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(function (response) {
console.log(response)
})
}
Make sure file is set in the data method as well:
data () {
return {
file: ''
}
}
I've created two components to send an image in base-64 encoded format to a server. When the parent component is mounted it's supposed to set the child reference to file.
Vue.component('some-form', {
template: '#some-form',
data: function() {
return {
logoImage: '',
coverImage: ''
}
},
methods: {
onSubmit: function(event) {
var dataForm = {};
var that = this;
dataForm['logo-image'] = this.logoImage;
dataForm['cover-image'] = this.coverImage;
// AJAX REQUEST HERE with posting data
},
},
mounted: function(){
var $this = this;
// AJAX REQUEST HERE with getting data
}
});
Vue.component('upload-photo', {
template: '#upload-photo',
data: function () {
return {
image: {
body: '',
'content-type': '',
'content-length': '',
url: ''
},
imageBody: ''
}
},
props: ['logoImage', 'title', 'description'],
watch: {
'image': function() {
this.$emit('input', this.image);
}
},
created: function(){
this.image = this.logoImage;
},
mounted: function () {
var that = this;
//AJAX REQUEST HERE to get data
},
methods: {
onFileChange: function(e) {
var files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
},
createImage: function(file){
var image = new Image();
var reader = new FileReader();
var vm = this;
vm.image = {};
reader.onload = function(e) {
vm.image.body = e.target.result;
vm.imageBody = e.target.result;
};
vm.$set(vm.image, 'content-type', file.type);
vm.$set(vm.image, 'content-length', file.size);
reader.readAsDataURL(file);
},
removeImage: function (e) {
this.image = '';
}
}
});
var app = new Vue({
el: '#app',
data: function() {
},
methods: {
},
mounted: function() {
}
});
Full example https://codepen.io/anon/pen/ZvzwzO
How can it be implemented?
P.S. I have no idea how to implement it in the same component. I send data as a string with two more property, however get as a string to, however it's link.
P.S.S. need just way to search.
It is difficult to tell exactly what you are asking but it sounds like you want to pass data from the parent component to the child. If you haven't already, read about Composing components and Dynamic Props for passing properties from a parent component to a child component.
One way to do this is to make the imageBody a property of the upload-photo component instead of part of the data.
props: ['logoImage', 'title', 'description', 'imageBody'],
Then have the parent supply a value for that property:
<upload-photo v-model="logoImage" title="TITLE 1" description="description_1" v-bind:image-body="imageBody">
Take a look at this phpfiddle. When the form is mounted, it sends an AJAX call back to the server to retrieve a URL, then sets the property on that first upload-photo child element to the URL sent back from the server in the AJAX response. Note that the upload-photo template was changed to show the image if imageBody is truthy instead of image.
I'm using Angular 2 with Spring MVC. I currently have an Upload component that makes an AJAX call to the Spring backend and returns a response of parsed data from a .csv file.
export class UploadComponent {
uploadFile: function(){
var resp = this;
var data = $('input[type="file"]')[0].files[0];
this.fileupl = data;
var fd = new FormData();
fd.append("file", data);
$.ajax({
url: "uploadFile",
type: "POST",
data: fd,
processData: false,
contentType: false,
success: function(response) {
resp.response = response;
},
error: function(jqXHR, textStatus, errorMessage) {
console.log(errorMessage);
}
});
};
}
This works, I get a valid response back; however, is there a more angular 2 way to pass this file to Spring and receive a response? I've been looking into creating an injectible service and using subscribe, but I've been struggling to get a response back
I ended up doing the following:
import { Component, Injectable } from '#angular/core';
import { Observable} from 'rxjs/Rx';
const URL = 'myuploadURL';
#Component({
selector: 'upload',
templateUrl: 'upload.component.html',
styleUrls: ['upload.component.css']
})
export class UploadComponent {
filetoUpload: Array<File>;
response: {};
constructor() {
this.filetoUpload = [];
}
upload() {
this.makeFileRequest(URL, [], this.filetoUpload).then((result) => {
this.response = result;
}, (error) => {
console.error(error);
});
}
fileChangeEvent(fileInput: any){
this.filetoUpload = <Array<File>> fileInput.target.files;
}
makeFileRequest(url: string, params: Array<string>, files: Array<File>) {
return new Promise((resolve, reject) => {
let formData: any = new FormData();
let xhr = new XMLHttpRequest();
for(let i =0; i < files.length; i++) {
formData.append("file", files[i], files[i].name);
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.response));
} else {
reject(xhr.response);
}
}
};
xhr.open("POST", url, true);
xhr.send(formData);
});
}
}
I can then inject a response into my html like:
<div class="input-group">
<input type="file" id="file" name="file" placeholder="select file" (change)="fileChangeEvent($event)">
<input type="submit" value="upload" (click)="upload()" class="btn btn-primary">
</div>
<div *ngIf="response">
<div class="alert alert-success" role="alert">
<strong>{{response.myResponseObjectProperty | number}}</strong> returned successfully!
</div>
This has support for multiple file uploads. I created it as an injectable service in this plunkr:
https://plnkr.co/edit/wkydlC0dhDXxDuzyiDO3