Vue JS Multiple File Upload With Preview - onlyxcodes

Friday, 9 July 2021

Vue JS Multiple File Upload With Preview

Friends, welcome back to this tutorial, which will show you how to use Vue JS to upload multiple files using the Axios process and PHP as the backend. File upload is a primary concept that each web-based application must have to save or upload files to the server. 


But, uploading files using VueJS and Axios might be a little difficult because it necessitates using an AJAX-based approach. 


Using VueJS and Axios, this tutorial solves the issues of multiple files uploading. 


It will walk you through how to use Axios to pass multiple files from the front end (VueJS) to your backend (PHP). When you've transferred the attachments to PHP, they'll be transformed into uploaded file objects. After that, you'll be able to easily upload multiple files to the server.


Let's make it much easier. 


Vue JS Multiple File Upload With Preview

Create Table

To hold the uploaded multiple file names, a table in the database is necessary. This command will start the database schema and construct the tbl_file table in your MySQL database with the table columns listed below. 


CREATE TABLE IF NOT EXISTS `tbl_file` (
  `id` int(11) NOT NULL,
  `user_picture` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Take a look at a practical demonstration of how this app works. 


Vue JS Multiple File Upload With Preview Practical Demo - image - codepen - component - axios - progress - files -  bootstrap-vue

index.html

In this file, we've developed every client-side code, including HTML and Vue.js implementation. We must first include the essential libraries to use Vue.js with the Axios package.

Add the CSS libraries specified below before closing the </head> tag. 


<!-- Bootstrap CSS -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
	
<!-- BootstrapVue CSS -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/[email protected]/dist/bootstrap-vue.min.css" />
	
<!-- Bootstrap npm CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">

Include the Javascript libraries listed below before closing the </body> tag. 


<!-- Vuejs -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	
<!-- BootstrapVue js -->
<script type="text/javascript" src="//unpkg.com/[email protected]/dist/bootstrap-vue.min.js"></script>
	
<!-- Axios -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
	
<!-- Bootstrap js -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4" crossorigin="anonymous"></script>

In this division tag, all HTML material was import into an element with the id "multiplefileApp."


<div class="container" id="multiplefileApp">

</div>

Initialize VueJS


VueJS is integrated before the </body> element is closed. As you've seen, we have an id called #multiplefileApp. It means that VueJS has called in a component with the id multiplefileApp after all of the Vue functionality has been completed.


<script>
    var application = new Vue({
	  el: '#multiplefileApp',
    
	});    
</script>

Since initializing the Vue component, we create Data property and methods to handle multiple file upload events using the Axios progress.


Define two variables in the Data property. 


Boostrap caches the file's modal form properties. Using the label variable, we'll keep track of how many files will be uploaded.


allImages: [] - This array will save all image records from the server and display them in bootstrap-vue Grid cards. allImages: [] is an array.


The modal references property is used by the method's showModal() and hideModal() functions to show and hide modal behavior.


<script>
    var application = new Vue({
	  el: '#multiplefileApp',
      data: {
        label: 'Choose file',
        allImages:[]
      },

      methods: {
        showModal(id) {
          this.$refs['upload-modal'].show()
        },
        hideModal(id) {
          this.$refs['upload-modal'].hide()
        },

		onChangeInput(){
			
        },
		  
		onUpload(){
		  
		},

        getAllRecords(){
		  
		}
          
      },
      mounted: function(){
        this.getAllRecords()
      }
    })

</script>

Let's take a look at the multiple file upload progress step by step.


To start, open a modal like the one shown above. I put it next to the browse button. The @click event is used to display this modal.


Underneath the dividing parts, I installed the bootstrap upload modal. Within this modal, I included a form with a file input type field. 


In the form tag, look for @submit.prevent="onUpload." It means that we run onUpload instead of submitting the form normally. We create an onUpload() function method within the Vue method that makes an Axios call to PHP to upload multiple images and then redirects to the bootstrap grid card for display.


<div class="card-header">
    <div class="d-flex d-flex justify-content-between">    
        <div class="lead"><button id="show-btn" @click="showModal('upload-modal')" class="btn btn-sm btn-outline-primary">Browse</button></div>
    </div>
</div>

<!-- File Upload Modal Start-->
<b-modal ref="upload-modal" hide-footer title="Browse and Upload Multiple Files">
    <form @submit.prevent="onUpload">
        <div class="mb-3">
			<input class="form-control" 
				type="file" 
				@change="onChangeInput($event.target.files)" 
				accept="image/*" multiple="multiple"
			/>
			<label class="form-label">{{label}}</label>
		</div>
		<br />
        <div class="form-group">
            <button class="btn btn-sm btn-outline-success">Upload</button> &nbsp;
			<b-button class="btn btn-sm btn-outline-danger" variant="outline-danger" block @click="hideModal('upload-modal')">Close
			</b-button>
        </div>
    </form>
</b-modal>
<!-- File Upload Modal End -->

explanation:


We need to add <input type=" file" /> to our component template code to allow the user to select a file. The multiple attributes indicate that multiple files can be uploaded. Remove it if you're only uploading a single file.


With the property accept=" image/*," we permit the file input to only allow images.


The file input change event will be handled by us. When someone drags or selects files, the file input changes. We'll use the onChangeInput method to provide the control name and selected files $event.target.files to the onChangeInput function and then upload them to the server.


When the file's label changes, we record it. In order to display the number of files uploaded, we use the {{ label }} variable.


VueJs code:


The onChangeInput method is used to handle file changes events.


I paste images variable in the onChangeInput() method. The images variable is an array variable that is declared in the.then( ) response function, as seen by images = [ ]. After the onChangeInput() event, this variable returns the number of images uploaded and their length. 


Look at this code application.onChangeInput(images).


The onUpload() function created within the VueJS method is triggered when you click the Upload button below.


<script>
    var application = new Vue({
      el: '#multiplefileApp',
      data: {
        label: 'Choose file',
        allImages:[]
      },

      methods: {
        showModal(id) {
          this.$refs['upload-modal'].show()
        },
        hideModal(id) {
          this.$refs['upload-modal'].hide()
        },

	  onChangeInput(images){
		if(images.length == 0)
		{
		  this.label = 'Choose file'
		}
		else if(images.length == 1)
		{
		  this.label = images[0]['name'] 
		}
		else if(images.length > 1 )
		{
		  this.label = images.length + 'files'
		}
      },
		  
	  onUpload(event){
		  
	    var fd = new FormData()
		    
		var photos = event.target[0].files
			
		if(photos.length !==0)
		{
			for(var a = 0; a < event.target[0].files.length; a++)
			{
				fd.append('img[]', photos[a])  
			}
			
			axios({
			 url: 'upload.php',
			 method: 'post',
			 data: fd,
			 headers: {
			   'Content-Type' : 'multipart/form-data'
			 }
			})
			.then(response => {
			  if(response.data.result == 'success')
			  {
			   alert('Image Uploaded Successfully :) ');
			   
			   images = []
				   
			   application.onChangeInput(images)
				   
			   application.hideModal();
				   
			   application.getAllRecords();
			  }
			  else
			  {
			    alert('error');
			  }
			})
			.catch(error => {
			  console.log(error)
			})
		}
		else
		{
		  alert('Sorry, File is Empty');
		}
	  },

      getAllRecords(){
        //
      },

     },

     mounted: function(){
	   this.getAllRecords()
     }
	 
   })

</script>

explanation:


Okay, thus far everything has made sense, but what exactly is this FormData? 


"You can use the FormData object to create a set of key/value pairs that you can send using XMLHttpRequest. It's primarily designed for sending form data, although it can also be used to convey keyed data without using forms."


The file values are given using the formData.append() process, and the fd variable is utilized to construct a new FormData() object. 


var fd = new FormData()

$event.target.files assign its handle file name and selected files to the new photos variable.


var photos = event.target[0].files

If the photos variable-length value is not 0, then if the condition is true, and the codes continue. 


if(photos.length !==0)
{

Now we'll loop through all of the files we've picked and add them to the img[] array we'll submit to the server. The img[] array will be used as a key in the FormData fd() object we'll send to the server: 


This loops through the files that the user has selected and prepares them for submission to the server.


The files can be accessed on the server using the key of files argument, which is the first parameter of the fd.append('img[]', photos[a]) method.


for(var a = 0; a < event.target[0].files.length; a++)
{
	fd.append('img[]', photos[a])  
}

We're now ready to use the Axios method to deliver our files to the server: 

The Axios uses an HTTP POST request to transfer the selected files to the "upload.php" file. And the pass fd, to which we have appended the selected file, has been sent as data with the post request.


In order to enable file upload, we've additionally specified Content-Type:'multipart/form-data in the header. 


axios({
 url: 'upload.php',
 method: 'post',
 data: fd,
 headers: {
   'Content-Type' : 'multipart/form-data'
 }
})	

If the response returns the string "success," the alert popup with the message "file uploaded successfully" appears within the.then() procedure, and all images are displayed on the same pages without having to refresh the page. 


Otherwise, the .catch() method will display an appropriate error message in your browser's console.


Here, if(response.data.result == 'success '), The array "result" is derived from the "upload.php" file. It will produce a success string if the file was properly uploaded; otherwise, it will return an error string.


Here, we build an images name blank array that returns the length of the uploaded file, such as 1, 2, and so on. The images variable is pasted into the onChangeInput() event so that the selected and uploaded file lengths may be easily identified at the time the onChangeInput() event occurs.


The modal automatically hides after a successful file upload, and the getAllRecords() method previews all files or images.


.then(response => {
  if(response.data.result == 'success')
  {
	alert('Image Uploaded Successfully :) ');
			   
	images = []
				   
	application.onChangeInput(images)
				   
	application.hideModal();
				   
	application.getAllRecords();
  }
  else
  {
    alert('error');
  }
})
.catch(error => {
  console.log(error)
})

upload.php


On the backend, this file acts silently and communicates via an Axios HTTP POST request.

 

This file receives and accesses selected files via the $_FILES['img'] method before sending them to the modal class, which appropriately stores the file names in the table and uploads our folder path. 


The model class, which holds all database-related information, is included here. 


When $model->insert is executed, it saves all of the file names in the table and returns a success string via the result array variable.


<?php 

	if (isset($_FILES['img'])) 
	{

		include 'model.php';

		$model = new Model();

		if ($model->insert($_FILES['img'])) 
		{
			$data = array('result' => 'success');
		}
		else
		{
			$data = array('result' => 'error');
		}

		echo json_encode($data);
	}

 ?>

model.php


The PHP Class that we create is known as a Model. These PHP Classes are used to implement Object-Oriented Programming in PHP. PHP Classes are used to bind the table values for the database. We'll define the values that will be saved in a variable form in the SQL database.


<?php 

	Class Model
	{
		private $host = 'localhost';
		private $username = 'root';
		private $password = '';
		private $dbname = 'vuejs_multiplefile_upload';
		private $connection;

		//create connection
		public function __construct()
		{
			try 
			{
				$this->connection = new mysqli($this->host, $this->username, $this->password, $this->dbname);
			} 
			catch (Exception $e) 
			{
				echo "Connection error " . $e->getMessage();
			}
		}

		// insert multiple images into database table
		public function insert($data)
		{
			$upload_dir = "upload/";
			
			for($a = 0; $a < count($data['name']); $a++)
			{
				$name = $data['name'][$a];
				$type = $data['type'][$a];
				$size = $data['size'][$a];
				$temp = $data['tmp_name'][$a];
				
				$path = $upload_dir . $name;
				
				move_uploaded_file($temp, $path);
				
				$query = "INSERT INTO tbl_file (user_picture) VALUES ('".$name."')";
				$sql = $this->connection->query($query);
			}
			if($sql) 
			{
				return true;
			}
			else
			{
				return;
			}
		}

		//fetch all images record from database
		public function fetchAll()
		{
			//
		}

	}

 ?>

__construct() — This function makes the database connection within the try/catch block. If an exception is thrown, it can be handled quickly.


The insert() function saves the names of selected files in the database and returns true.


The $upload_dir variable is used to store the path "upload/" to the file uploading folder. 


The count() function is used inside the for loop to count the names of the files that have been selected.


The names of the files are concatenated with the path to our upload directory. 


The move uploaded file() function moves files from a temporary location to the upload folder path we specified.


The insert query adds the name of a file or an image to the table. If the SQL query is correctly executed, the insert() function will return true.


Preview All Images:


Bootstrap-vue Grid cards are used to display the images. I use specific vue attributes and bind them to the div components so that the images can be displayed as I want. 


To repeat all of the "allImages," we used the v-for directive. 


We preview all images using the image tag, and we preview all images from our upload folder path using the src attribute tag. 


Understand this code :src=" 'upload/' image + user_picture ".


The upload is the path to our directory where we have uploaded all of our images, The image variable iterates across all records, and user_picture is the name of a table column. 


<div class="row row-cols-1 row-cols-md-3" v-if="allImages.length">
	<div class="col" v-for="image in allImages" :key="image.id">
		<div class="card">
			<img :src="'upload/' + image.user_picture" class="card-img-top">
		</div>
	</div>
	<div class="text-center" v-if="!allImages.length">
		<p class="text-muted">Empty</p>
	</div>
</div>

VueJs code:


There's a hook named mounted in Vue. This hook is called whenever a page or a Vue instance is launched. 


So, in this hook, I call a method called "getAllRecords ()," which calls the read.php file, which fetches the data of the file and displays it.


mounted: function(){
  this.getAllRecords()
}

The Axios function sends a request to the read.php file and uses the getAllRecords () method to retrieve all of the file's records.


Within the .then() method, the data is stored in the variable "allImages" and iterating (v-for) this variable displays all of the images required for the preview.


The allImages array was defined in the data property. 


Here, this. allImages= response.data.rows, The final "rows" parameter is an array obtained from the read.php file, which returns all table records as an array.


<script>
    var application = new Vue({
      el: '#multiplefileApp',
      data: {
        label: 'Choose file',
        allImages:[]
      },

      methods: {
        showModal(id) {
          this.$refs['upload-modal'].show()
        },
        hideModal(id) {
          this.$refs['upload-modal'].hide()
        },

	  onChangeInput(images){
		//
      },
		  
	  onUpload(event){
		//  
	  },

      getAllRecords(){
        axios({
         url: 'read.php',
         method: 'get'
        })
        .then(response => {
          console.log(response);
		  if(response.data.result == 'success'){
		    this.allImages = response.data.rows
		  }
        })
        .catch(error => {
          console.log(error)
        })
      },

     },
	 
     mounted: function(){
	   this.getAllRecords()
     }
	 
   })

</script>

read.php


This file was created via an Axios HTTP POST request. If $model->fetchAll is executed, all table records are delivered to the rows array variable. 


<?php 

	include 'model.php';

	$model = new Model();

	if ($rows = $model->fetchAll()) 
	{
		$data = array('result' => 'success', 'rows' => $rows);
	}
	else
	{
		$data = array('result' => 'error');
	}

	echo json_encode($data);
	
 ?>

model.php class code


The fetchAll() function fetches all of the images data from the database and delivers it, which is then displayed on the preview using VueJS.


<?php 

	Class Model
	{
		private $host = 'localhost';
		private $username = 'root';
		private $password = '';
		private $dbname = 'vuejs_multiplefile_upload';
		private $connection;

		//create connection
		public function __construct()
		{
			try 
			{
				$this->connection = new mysqli($this->host, $this->username, $this->password, $this->dbname);
			} 
			catch (Exception $e) 
			{
				echo "Connection error " . $e->getMessage();
			}
		}

		// insert multiple images into database table
		public function insert($data)
		{
			//
		}

		//fetch all images record from database
		public function fetchAll()
		{
			$data = [];

			$query = "SELECT * FROM tbl_file";

			if ($sql = $this->connection->query($query)) 
			{
				while ($rows = mysqli_fetch_assoc($sql)) 
				{
					$data[] = $rows;
				}
			}

			return $data;
		}

	}

 ?>

Read Also — VueJS CRUD Operation With PHP & MySQL


Download Codes

2 comments:

  1. where is preview and delete??

    ReplyDelete
    Replies
    1. See preview code available above. In this tutorial I not include delete code only upload and preview code included

      Delete