<template>
<v-app id="inspire" dark >
<v-layout v-for = "post in posts" :key = "post.id">
<v-flex xs3>
<v-card >
<v-card-media>
<img
:src = "post.postImage">
</v-card-media>
<v-card-title>
{{post.description}}
</v-card-title>
</v-card>
</v-flex>
</v-layout>
</v-app>
</template>
<script>
import PostService from '#/service/PostService'
export default {
data(){
return {
posts: []
}
},
mounted (){
this.getPosts()
},
methods: {
async getPosts() {
const response = await PostService.fetchPosts()
this.posts = response.data.posts
}
}
}
</script>
const multer = require('multer');
const Post = require('./models/post')
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './uploads/');
},
filename: (req, file, cb ) => {
cb(null, Date.now() + file.originalname);
}
})
const fileFilter = (req, file, cb) => {
if(file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
}else {
cb(null, false);
}
}
const upload = multer({
storage: storage,
fileFilter,
limits: {
fileSize: 1024 * 1024 * 5
}
});
app.get('/posts', (req, res) => {
Post.find({},'postImage description', (error, posts) => {
if(error) {
console.log(error)
}
res.send({
posts
})
}).sort({_id: -1})
})
Hi all, i was about to display images using multer on my front end. but it does only show imagelink or image destination, but i already added some images in my backend. So how can i show images to my front-end using vue dynamically. I did use v-for for each data in my database. what should i input to my v-card-media to get images dynamically.
Related
When I try to upload a user photo with Vue, the formData just seems to be an empty object. The Multer middleware then fails because there is no req.file for it read.
User.vue
<form enctype="multipart/form-data">
<div class="pl-3 label">User Photo</div>
<v-file-input
accept='image/*'
label="Upload Photo"
v-model="photo"
></v-file-input>
<v-btn class="mr-5" color="blue lighten-3" #click="submit">
save changes
</v-btn>
export default {
data: () => ({
photo: null
}),
methods: {
submit() {
let formData = new FormData();
if (this.photo) {
formData.append('photo', this.photo)
}
this.$store.dispatch('updateMe', {
photo: formData
});
}
}
};
Vuex Store
export default new Vuex.Store({
state: {
photo: null
},
mutations: {
setUpdatedUser(state, payload) {
state.name = payload.name;
state.email = payload.email;
state.photo = payload.photo;
}
},
actions: {
async updateMe({ commit, getters }, payload) {
let id = localStorage.getItem('userId');
let user = {
photo: payload.photo
};
try {
let token = getters.token;
const response = await axios.patch(
`http://localhost:3000/api/v1/users/updateMe`,
user,
{
headers: { Authorization: 'Bearer ' + token }
}
);
commit('setUpdatedUser', response.data.updatedUser);
} catch (err) {
console.log(err);
}
}
}
User Controller
const multerStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/users');
},
filename: (req, file, cb) => {
console.log(file)
const ext = file.mimetype.split('/')[1];
cb(null, `user-${req.user.id}-${Date.now()}.${ext}`);
}
});
const multerFilter = (req, file, cb) => {
if (file.mimetype.startsWith('image')) {
cb(null, true);
} else {
cb(new AppError('Not an image. Please upload only images.', 400), false);
}
};
const upload = multer({
storage: multerStorage,
fileFilter: multerFilter
});
exports.uploadUserPhoto = upload.single('photo');
Most other examples I have compared to do not use v-model for the input binding. Does that make a difference?
In an application where I am handling file uploads the files get posted to the node backend.
I also v-model in my component so that shouldn't be the problem.
Frontend method:
upload() {
const data = new FormData()
data.append('file', this.file, this.file.name) // Filename is optional
data.append('additionalInformation', this.additionalInformation)
axios.
post('/api/v1/upload/', data)
.then(response => /* response handling */)
.catch(error => /* error handling */)
}
The node endpoint looks like this:
app.post('/api/v1/upload/', multer().single('file'), (request, response) => {
upload(request.body, request.file, response, config)
})
Reference: FormData.append()
I would like to create an upload progress bar with Axios.
Everything is working fine with server sending and response.
The problem is that I don't know how to capture the progress percentage (which is correctly calculated) from my exported object.
My file upload.js:
import axios from 'axios'
const baseUrl = 'http://localhost:80/upload.php'
const config = {
Headers: {'Content-Type': 'multipart/form-data'},
onUploadProgress: progressEvent => {
return parseInt(Math.round((progressEvent.loaded / progressEvent.total) * 100))
}
}
export default {
send (data) {
return axios.post(baseUrl, data, config)
}
}
My Vue component:
<template>
<div>
<label>File:</label>
<input type="file" id="file" ref="file" #change="changeFile()" />
<button #click="submit()">Upload</button>
<br />
<progress max="100" :value.prop="uploadPercentage"></progress>
</div>
</template>
<script>
import upload from '../services/upload.js'
export default {
name: 'Upload',
data: () => ({
file: null,
uploadPercentage: 0
}),
methods: {
submit () {
const formData = new FormData()
formData.append('file', this.file)
upload.send(formData)
.then(res => {
console.log(res.data)
})
.catch(() => {
console.log('Failure')
})
},
changeFile () {
this.file = this.$refs.file.files[0]
}
}
}
</script>
How to retreive, from the component submit method, the info sent by the onUploadProgress in order to update the data uploadPercentage?
Thanks.
Regards.
You need to pass a function to your send operation that will be called later.
See example below
const config = {
Headers: {'Content-Type': 'multipart/form-data'},
onUploadProgress: progressEvent => {
var progress= parseInt(Math.round((progressEvent.loaded / progressEvent.total) * 100));
if (config.onProgress)
config.onProgress(progress);
}
}
export default {
send (data, onProgress) {
config.onProgress= onProgress;
return axios.post(baseUrl, data, config)
}
}
Then you upload code will be
upload.send(formData,(pogress)=>{
// Update your uploadPercentage here
})
.then(res => {
console.log(res.data)
})
.catch(() => {
console.log('Failure')
})
I am trying to figure out how to upload multiple files to my S3 bucket but can't seem to figure it out. I am running a Nuxt.js app with express api. I am just testing out 1 or 2 files to upload, but get a 500 response with the error:
Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1.
My Vue Template: /pages/add.vue
<template>
<v-col cols="12">
<h2 class="display-1 font-weight-light mb-5">Add Photos</h2>
<v-form
ref="uploadForm"
v-model="valid"
enctype="multipart/form-data"
lazy-validation
#submit.prevent="submitFiles"
>
<v-row>
<v-col cols="12" sm="6">
<v-file-input
v-model="photos"
:counter="30"
:rules="uploadRules"
accept="image/png, image/jpeg"
show-size
multiple
label="Click to upload photos"
/>
</v-col>
<v-col cols="12" sm="6">
<v-btn :loading="loading" color="primary" #click="submitFiles()">
Upload
</v-btn>
</v-col>
</v-row>
</v-form>
</v-col>
</template>
<script>
export default {
layout: 'admin',
data: () => ({
photos: [],
uploadRules: [(v) => (v && v.length <= 30) || 'No more than 30 files'],
valid: true,
loading: false
}),
methods: {
submitFiles() {
if (this.$refs.uploadForm.validate()) {
this.loading = true
const formData = new FormData()
const Form = this
for (let i = 0; i < this.photos.length; i++) {
const file = this.photos[i]
formData.append(`photos['${i}']`, file)
}
this.$axios
.post('/photos/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then((res) => {
console.log('success')
console.log(res)
})
.catch((error) => {
console.log('fail')
console.log(error)
})
.finally(() => {
Form.loading = false
Form.photos = []
})
}
}
}
}
</script>
my upload file: /utils/upload.js
const aws = require('aws-sdk')
const multer = require('multer')
const multerS3 = require('multer-s3')
const s3 = new aws.S3()
aws.config.update({
apiVersion: '2006-03-01',
accessKeyId: process.env.AWS_KEY,
secretAccessKey: process.env.AWS_SECRET,
region: process.env.AWS_REGION_APP
})
const upload = multer({
storage: multerS3({
s3,
bucket: process.env.BUCKET,
acl: 'public-read',
metadata: (req, file, cb) => {
cb(null, { fieldName: file.fieldname })
},
key: (req, file, cb) => {
cb(null, Date.now().toString())
}
})
})
module.exports = upload
My Express api: /api/photos.js
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
app.use(bodyParser.json())
const upload = require('../utils/upload')
// Upload photos
app.post('/upload', upload.array('photos', 3), (req, res) => {
res.send('Successfully uploaded ' + req.files.length + ' files!')
})
module.exports = app
I'm still not exactly sure why, but after I installed aws-cli to test my credentials, it worked.
I also updated part of the code in the add.vue file
from:
for (let i = 0; i < this.photos.length; i++) {
const file = this.photos[i]
formData.append(`photos['${i}']`, file)
}
to:
for (let i = 0; i < this.photos.length; i++) {
formData.append(`photos`, this.photos[i])
}
I have vue SPA and I trying to upload some images and text. I try using postman to test my server code and it's work, but my client-side still error.
I think I'm still mistaken for handle req.file.
addImage.vue
<template>
<div>
<b-form-group label-cols-sm="3" description="image title" label="Title">
<b-form-input v-model="newImage.title"></b-form-input>
</b-form-group>
<b-form-group label="my Image" label-for="file" label-cols-sm="2">
<b-form-file id="file" v-model="newImage.image"></b-form-file>
</b-form-group>
<b-button variant="primary" class="pl-5 pr-5" #click.prevent="addImage">Save</b-button>
</div>
</template>
<script>
export default {
data() {
return {
newImage: {
title: '',
image: null,
},
};
},
methods: {
addImage() {
this.$store.dispatch('addProduct', this.newProduct);
}
},
};
store.js
actions: {
addImage(context, newImage) {
const config = {
headers: {
token: localStorage.getItem('token'),
},
};
Axios
.post(`${baseUrl}/product`, newImage, config)
.then(({ newImage }) => {
context.commit('ADD_IMAGE', newImage);
})
.catch((err) => {
console.log(err.message);
});
}
}
When you want to upload an image you have to set the content type and create FormData, like this:
let data = new FormData();
for (var i = 0; i < files.length; i++) {
let file = files.item(i);
data.append('images[' + i + ']', file, file.name);
}
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
return axios.post('/api/images', data, config)
I use VueJS (cli 3) & axios, and NodeJS - ExpressJS in the back-end. I am trying to secure my post user edit using CSRF token.
Vue View (edit user - focus to mySubmitEd):
<template>
<div class="one-user">
<h1>this user</h1>
<h2>{{name}} - {{surname}} - {{ perm }}</h2>
<h2>Edit</h2>
<input type="text" v-model="name">
<input type="text" v-model="surname">
<input type="text" v-model="perm">
<button #click="mySubmitEd">Edit</button>
<button #click="mySubmit">Delete</button>
</div>
</template>
<script>
import axios from 'axios'
import io from 'socket.io-client'
export default {
name: 'one-user',
data () {
return {
name: '',
surname: '',
perm: '',
csrf: '',
id: this.$route.params.id,
socket: io('localhost:7000')
}
},
mounted () {
axios.get('http://localhost:7000/api/get-user/' + this.id)
.then(res => {
const data = res.data.user
this.name = data.name
this.surname = data.last_name
this.perm = data.permalink
this.csrf = res.data.csrfToken
axios.defaults.headers.common['X-CSRF-TOKEN'] = this.csrf
})
.catch(error => console.log(error))
},
methods: {
mySubmit () {
const formData = {
_id: this.id
}
axios.post('http://localhost:7000/api/delete-user', formData)
.then(this.$router.push({ name: 'get-user' }))
.catch(error => console.log(error))
},
mySubmitEd () {
const formData = {
_id: this.id,
name: this.name,
last_name: this.surname,
permalink: this.perm,
_csrf: this.csrf
}
console.log(formData._csrf)
axios.post('http://localhost:7000/api/update-user', formData)
.catch(error => console.log(error))
}
}
}
</script>
server.js file:
...
const cookieParser = require('cookie-parser');
const csurf = require('csurf');
...
app.use(cookieParser());
const csrfProtection = csurf({ cookie: true });
app.use(csrfProtection);
...
back-end controller which get the user:
controller.getOneUser = function(req, res) {
User.findOne({ _id: req.params.userId }).exec(function(err, user) {
res.json({user, csrfToken: req.csrfToken()});
});
};
back-end update post:
controller.updateUser = function(req, res) {
User.findById(req.body._id, function(err, user) {
user.set({
name: req.body.name,
last_name: req.body.last_name,
permalink: req.body.permalink,
price: req.body.price
});
user.save();
res.send(user);
});
};
My errors in NodeJS-exress console:
ForbiddenError: invalid csrf token
My errors in browser:
POST http://localhost:7000/api/update-user 403 (Forbidden)
I don't know what is happened because I see in network tab(chrome) the csrf token is the same in the headers and what I send (ex.):
X-CSRF-TOKEN: PddyOZrf-AdHppP3lMuWA2n7AuD8QWFG3ta0
_csrf: "PddyOZrf-AdHppP3lMuWA2n7AuD8QWFG3ta0"
I don't know what I have miss here. I can't find where is the problem.
If you want more information please asked me to help you.
I had to pass in the headers the cookie correctly, so I did 2 corrections:
First in Vue view:
I passed credentials:
axios.create({withCredentials: true}).get(...)
and
axios.create({withCredentials: true}).post(...)
and secondly in server.js file before routes I put this:
...
const corsOptions = {
origin: 'http://localhost:8080',
credentials: true,
}
app.use(cors(corsOptions));
app.use(bodyParser.json());
app.use(cookieParser());
const csrfProtection = csurf({ cookie: true });
app.use(csrfProtection);
app.use(function (req, res, next) {
res.cookie('XSRF-TOKEN', req.csrfToken());
res.locals._csrf = req.csrfToken();
next();
});
...