How to Upload Multiple Image/File in Vue using Axios

A detailed tutorial on vue Axios post multipart/form-data, in this example, we will teach you how to create vue multiple image upload components using the node js, express js, multer and also explain how to make HTTP post request using Axios and form-data to post images to server and store multiple images in the MongoDB database.

Axios is a renowned promise-based HTTP client, essentially works on the browser and node and doesn’t let occurring any discord in making HTTP requests.

The FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be quickly sent using the XMLHttpRequest.

File uploading is the primary feature of any application. This extensive vue upload multiple files tutorial will be a perfect payback for novice developers, and we will try to show the right path with pragmatic solutions.

Vue JS Axios Multiple Image/File Upload Example

  • Step 1: Create Vue Project
  • Step 2: Add Bootstrap CSS Package
  • Step 3: Add Axios Library
  • Step 4: Create Vue Component
  • Step 5: Build Multiple File Upload REST API
  • Step 6: Implement Multiple Images Upload in Vue
  • Step 7: Run Vue + Node Server

Create Vue Project

Start with creating a new vue project; after that, enter into the project.

vue create vue-fluff-potato
cd vue-fluff-potato

Add Bootstrap CSS Package

Next, invoke the installation of bootstrap CSS library in vue to create rapid ui components.

npm install bootstrap

In order proliferate the usage of Bootstrap in vue, make sure to add the css path in the src/main.js file.

import Vue from 'vue'
import App from './App.vue'

import 'bootstrap/dist/css/bootstrap.css'

new Vue({
  render: h => h(App),
}).$mount('#app')

Add Axios Library

Further, execute the following command to install the axios package.

npm install axios

Axios is not an ordinary library, with it you can:

  • Make XMLHttpRequests from the browser
  • Make http requests from node.js
  • Supports the Promise API
  • Intercept request and response
  • Transform request and response data
  • Cancel requests
  • Automatic transforms for JSON data
  • Client side support for protecting against XSRF

Build Vue Component

Go ahead and create a new MultiUpload.vue file, ensure that this file is created within the components folder.

Plus, register the newly created component in the src/App.vue file.

<template>
  <div class="container mt-4 text-center">
    <MultiUpload />
  </div>
</template>

<script>
    import MultiUpload from './components/MultiUpload.vue'
    export default {
      name: 'App',
      components: {
        MultiUpload
      } 
    }
</script>

Build Multiple File Upload REST API

Create a `backend` folder within the vue app’s root.

Including, generate a package.json file for handling the Node and Express server using the npm initializer command.

npm init

Now, execute given commands to add required dependencies.

npm install multer express mongoose body-parser cors uuid

The nodemon library starts the node server repeatedly when it finds a new change in the server files.

npm install nodemon --save-dev

In the backend folder, create db folder and database.js file, then define the MongoDb settings.

Update code in backend/db/database.js file.

module.exports = {
    db: 'mongodb://localhost:27017/vuedb'
}

Next, create a file upload schema that holds the logical structure of the file upload object.

So, create models folder, File.js file and update the below code in the backend/models/File.js file.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const fileSchema = new Schema({
    _id: mongoose.Schema.Types.ObjectId,
    imagesArray: {
        type: Array
    }
}, {
    collection: 'files'
})

module.exports = mongoose.model('File', fileSchema)

Next, create routes folder in backend then create file.route.js file, after that update the provided code in backend/routes/file.route.js file.

let express = require('express');
let mongoose = require('mongoose');
const { v4: uuidv4 } = require('uuid');
let multer = require('multer');
let router = express.Router();

const DIR = './public/';
let File = require('../models/File');


const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, DIR);
    },
    filename: (req, file, cb) => {
        const fileName = file.originalname.toLowerCase().split(' ').join('-');
        cb(null, uuidv4() + '-' + fileName)
    }
});


var upload = multer({
    storage: storage,
    fileFilter: (req, file, cb) => {
        if (file.mimetype == "image/png" || file.mimetype == "image/jpg" || file.mimetype == "image/jpeg") {
            cb(null, true);
        } else {
            cb(null, false);
            return cb(new Error('File type not accepted (.png, .jpg, .jpeg)'));
        }
    }
});

router.post('/multi-images-upload', upload.array('imagesArray', 8), (req, res, next) => {
    const reqFiles = [];

    const url = req.protocol + '://' + req.get('host')

    for (var i = 0; i < req.files.length; i++) {
        reqFiles.push(url + '/public/' + req.files[i].filename)
    }

    const user = new File({
        _id: new mongoose.Types.ObjectId(),
        imagesArray: reqFiles
    });

    user.save().then(result => {
        res.status(201).json({
            message: "Uploaded!",
            userCreated: {
                _id: result._id,
                imagesArray: result.imagesArray
            }
        })
    }).catch(err => {
        console.log(err),
            res.status(500).json({
                error: err
            });
    })
})

router.get("/", (req, res, next) => {
    File.find().then(response => {
        res.status(200).json({
            message: "Images fetched!",
            posts: response
        });
    });
});

module.exports = router;

We need to create a public folder; in this folder, uploaded files will be kept.

You may manually create a public directory in the backend folder or may use the following command.

mkdir public

Eventually, we need to create an index.js file in the backend; this file ideally manages node app startup, routing, and other essential functions.

Update code in backend/index.js file.

let express = require('express');
let mongoose = require('mongoose');
let bodyParser = require('body-parser');
let mongo = require('./db/database');
let cors = require('cors');

const REST_API = require('../backend/routes/file.route')

mongoose.Promise = global.Promise;
    mongoose.connect(mongo.db, {
        useUnifiedTopology: true,
        useNewUrlParser: true
    }).then(() => {
        console.log('Database connected')
    },
    err => {
        console.log(err)
    }
)

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));

app.use(cors());

app.use('/public', express.static('public'));
app.use('/api', REST_API)

const port = process.env.PORT || 8888;

app.listen(port, () => {
    console.log('Connected : ' + port)
})

app.use((req, res, next) => {
    setImmediate(() => {
        next(new Error('Error occurred'));
    });
});

Implement Multiple Images Upload in Vue

Next, head over to the multiple-image component, create the file upload form, create the custom function, and use the express API to load the multiple images in vue using Axios.

Update code in components/MultiUpload.vue file.

<template>
  <div>
      <form @submit.prevent="onUpload">
          <div class="form-group">
              <input type="file" name="imagesArray" multiple @change="onChange">
          </div>
          <div class="form-group">
              <button class="btn btn-success">Store</button>
          </div>
      </form>
  </div>
</template>

<script>
import axios from "axios";

export default {
  data() {
      return {
         imagesArray: null
      };
    },
    methods: {
        onChange (event) {
          this.imagesArray = event.target.files
        },
        onUpload() {
          const formData = new FormData();
          for (const i of Object.keys(this.imagesArray)) {
            formData.append('imagesArray', this.imagesArray[i])
          }
          axios.post('http://localhost:8888/api/multi-images-upload', formData, {
          }).then((res) => {
            console.log(res)
          })
        }  
    }

}
</script>

<style scoped lang="css">
.container {
  max-width: 550px;
}
</style>

Run Vue + Node Server

At the final stage of this journey, we have to evoke the vue development server using the given command.

npm run serve

Secondly, run below two commands on two different consoles to start the node server.

nodemon
mongo

On the below url, you may see the stored file’s data.

http://localhost:8888/api

Upload Multiple Images in Vue

Conclusion

In the initial section of this guide, we understood about creating the basic vue app, adding Axios library, creating reusable image upload component. In the second section of this guide, we developed an image upload REST API using node, express, multer.

Lastly, we accumulated all the things to make the POST request and post multipart form data to store multiple images on the server.