How to autosave form as draft in PHP and Ajax without page refresh

Autosaving of form data is a good option for a web form as users do not need to bother about saving the form as a draft. During data entry, the form can be automatically saved as a draft without page refresh. In this topic, we will develop an application to show how you can write PHP code with Ajax and jQuery to implement "Auto Save". There will be an application form and users can submit the form by filling up all the input fields.

The form can be saved as a draft after every few seconds and the user can work on it later to modify/complete the form and submit it.

save form data using ajax in phpFolders and Files

Below is a screenshot of the folder structure and files we will be using:

Save Form Using Ajax and PHP Without Page Refresh

We have a folder named 'autosave' under 'xampp/htdocs'.

Folder 'cfg' - In this folder we have dbconnect.php to connect to the MySQL database.
Folder 'css' - Our custom stylesheet is in this folder
Folder 'js' - In this folder we have our custom JavaScripts file
index.php is the main program that displays a list of submitted applications with options to view and edit.
application_form.php is the application form user can fill in and submit.
process_application.php is the php code written to process the application, that is, it does insert/update application data into the database table.
save_application.php - It is the PHP program called from Ajax to save application as draft.

Below is the screenshot of the application form.

save draft in PHP

While entering the values in the form, a JavaScript function will be called every 3 seconds. This function will run an Ajax script which will call a PHP program to save the application in database with status as draft. If you close the form, it will appear in the list of applications with status as draft. User can click on Edit button from the list of applications to further work on it and submit. When application is submitted it's status will change to "Submitted".

Create a table in MySQL for user applications

We will create a table named 'user_application' in MySQL database. This table will have application details, like name, email and age etc. Table structure is given below:

draft in ajax in php

Columns in the table are given below:

  1. appl_id - Primary key and auto incremented id of the application
  2. name - Name of the Applicant
  3. email - Email Id of the Applicant
  4. age - Age of the Applicant
  5. gender - Gender of the Applicant
  6. percent_score - %Score obtained by the applicant
  7. date - Date of submission or draft submission
  8. status - Application status(Draft or Submitted)
You can download the entire code including create table scripts given later in this topic.

user_application.sql


CREATE TABLE `user_application` (
  `appl_id` int(11) NOT NULL,
  `name` varchar(100) NOT NULL,
  `email` varchar(100) NOT NULL,
  `age` tinyint(4) NOT NULL,
  `gender` enum('Male','Female','Other') NOT NULL,
  `percent_score` decimal(5,2) NOT NULL,
  `date` date NOT NULL,
  `status` enum('Draft','Submitted') NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `user_application`
  ADD PRIMARY KEY (`appl_id`);

ALTER TABLE `user_application`
  MODIFY `appl_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;

PHP code to connect to MySQL database (dbconnect.php)

Use below script to connect to the database.

dbconnect.php


<?php
  $server="localhost";
  $userid="root";
  $pwd="";
  $dbname="test";
  $conn = mysqli_connect($server, $userid, $pwd, $dbname);
//Check connection
if (!$conn) 
  	die("Connection Error: " . mysqli_connect_error());

We are using mysqli_connect() function with four parameters.

  1. server - localhost
  2. userid - we are using root user
  3. password - no password for user root
  4. database name - test database.

We will include this dbconnect.php in other php programs to access the database. You can also read How to connect to MySQL database in PHP using MySQLi and PDO to know more about connecting to MySQL database using PHP.

Display a list of applications (index.php)

In index.php, we will display a list of applications with options to update and view. It is a simple html table, we will select all applications from the database table and display them along with their status (Draft or Submitted). For each application there will be a link to view (for submitted application) or edit (for draft application).

A sample list of applications:

Autosave draft using ajax in php

We are displaying details of each application using a for loop after fetching from the database. Let's see the code.

index.php


<!DOCTYPE html>
<html lang="en">
<head>
  <title>Online Application</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
  <link  rel="stylesheet" href="css/style.css">
</head>
<?php include "cfg/dbconnect.php";?>
<body>
  <div class="container">
    <h2>Online Application</h2>
	 	<h4>Application List<span class="appl"><a class="btn btn-primary" href="application_form.php">New Application</a></span></h4>
	 	<div class="table-responsive">
			 <table class="table table-bordered table-striped">
			 	<tr>
			 		<thead>
			 		<th>Appl No.</th><th width="150">Date Submitted (mm/dd/yyy)</th><th>Name</th><th>Email</th><th>Gender</th><th>Status</th><th>Action</th>
			 		</thead>
			 	</tr>
			 	<?php
			 	$select = "select * from user_application order by appl_id";
			 	$appl = mysqli_query($conn,$select); 
			 	$counter = 0;
			 	if (mysqli_num_rows($appl) >0){
			 		foreach ($appl as $appl_row) { 
				 		$appl_id = $appl_row['appl_id'];
				 		$status = $appl_row['status'];
				 		?>
				 		<tr>
				 			<td><?php echo $appl_row['appl_id'];?></td>
				 			<td><?php echo date('m/d/Y',strtotime($appl_row['date']));?></td>
				 			<td><?php echo $appl_row['name'];?></td>
				 			<td><?php echo $appl_row['email'];?></td>
				 			<td><?php echo $appl_row['gender'];?></td>
				 			<td><?php echo $appl_row['status'];?></td>
				 			<td>
				 				<a href="application_form.php?id=<?php echo $appl_id;?>"><?php if ($status == 'Draft') echo 'Edit';else echo 'View';?></a>
				 			</td>
						 </tr>
					 <?php } 
				 }
			 	else { ?>
			 		<tr><td colspan="7">No Application found.</td></tr>
			 		<?php } ?>
			</table>
		</div>
	</div>
</body>
</html>

In line 14, there is a button for "New Application" which calls application_form.php for the new application. Then we have defined an html table displaying all the applications. In line 39, we are checking the application status and showing View (Submitted) or Edit (Draft) links accordingly.

Create Application Form (application_form.php)

When the user clicks on the "New Application" button or clicks View/Edit links, this program will show the application form where user can enter the data and submit the form. While entering the data, the form will automatically be saved after every 3 seconds. If the user closes the form without submitting it, he/she can work on it later.

Clicking on Submit button will submit the form and will make the application status as Submitted. We will use process_application.php to process the application when it is submitted.

Below is the code for application_form.php

application_form.php


<!DOCTYPE html>
<html lang="en">
<head>
  <title>Online Application</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
  <link  rel="stylesheet" href="css/style.css">

</head>
<?php include "cfg/dbconnect.php";?>
<body>
  <div class="container">
  	<?php
		$appl_id = $name = $age = $gender = $email = $score = $status = "";
		$email_err = $age_err = $score_err = $err_flg = "";
		if (isset($_REQUEST['id']) && $_REQUEST['id'] != "") {
			$appl_id = $_REQUEST['id'];
			$rs = mysqli_query($conn,"select * from user_application where appl_id = '$appl_id'");
			if (mysqli_num_rows($rs) >0) {
				$row 		= mysqli_fetch_array($rs);
				$name 	= $row['name'];
				$email 	= $row['email'];
				$age 		= $row['age'];
				$gender = $row['gender'];
				$score 	= $row['percent_score'];
				$status = $row['status'];
				$date 	= $row['date'];
		 	}
		 	else
		 		$appl_id = ""; // Application id is not found, so take this as new application
		}
		include "process_application.php";
		if ($status == "Draft") {?> 
		  <h4>Update Application</h4>
		<?php } 
		elseif ($status == "") {?>
			<h4>New Application</h4>
		<?php } 
		else { ?>
			<h4>Submitted Application</h4>
		<?php } ?>
		<div class="showMsg"><span id ="msgSave"></span></div>
			<form id ="frm" action = "application_form.php" method = "post">
				<?php if ($status == "Draft" || $status == "") {?> 
							<input type="hidden" name="appl_id" id="appl_id" value="<?php echo $appl_id;?>"/>
			   <?php } else { ?>
			   			<div class="form-group col-md-12">
			   				<label style="width: 100%">Application No: <?php echo $appl_id;?> </label>
			   			</div>
			   <?php } ?>
					<div class="form-group col-md-12">
				 			<label>Name</label>
				 			<input <?php if ($status == "Submitted") {?> readonly <?php }?> type = "text" name="name" id = "name" class="form-control" maxlength="100" value="<?php echo $name;?>" placeholder="Enter Your Name" required>
					</div>
					<div class="form-group col-md-12">
					 	<label>Email Id</label>
					 	<input type="text" <?php if ($status == "Submitted") {?> readonly <?php }?> name="email" id ="email" class="form-control"  placeholder="Enter Email" value="<?php echo $email;?>" required>
					 	<span class="error"><?php if (!empty($email_err)) echo $email_err; $email_err = "";?> 
					</div>
					<div class="form-group col-md-12">
				 			<label>Age (Min 18, Max 35)</label>
				 			<input <?php if ($status == "Submitted") {?> readonly <?php }?> type = "number" name="age" id="age" class="form-control"  value="<?php echo $age;?>" placeholder="Enter Age" required>
				 			<span class="error"><?php if (!empty($age_err)) echo $age_err; $age_err = "";?> 
					</div>
					<div class="form-group col-md-12">
				 		<label>Gender</label>
					 	<select <?php if ($status == "Submitted") {?> readonly <?php }?> name="gender" id = "gender" class="form-control" required >
					 		<option value="">Select Gender</option>
					 		<option value="Male" <?php if ($gender == 'Male'){?> selected <?php } ?>>Male</option>
					 		<option value="Female" <?php if ($gender == 'Female'){?> selected <?php } ?>>Female</option>
					 		<option value="Other" <?php if ($gender == 'Other'){?> selected <?php } ?>>Other</option>
				 		</select>
				 	</div>
					
					<div class="form-group col-md-12">
						 <label>%Marks Obtained (Min 35%, Max 100%)</label>
						 <input <?php if ($status == "Submitted") {?> readonly <?php }?> type="number" name="score" id ="score" class="form-control"  placeholder="Enter Your Marks" value ="<?php echo $score;?>" required>
						 <span class="error"><?php if (!empty($score_err)) echo $score_err; $score_err = "";?>
					</div> 
					<div class="col-md-12 text-center">
						<?php if ($status == "Draft" || $status== "") {?> 
					 		<input type ="submit" name="submit" class="btn btn-primary" value="Submit">  
					 	<?php } ?>
					 		<a href="index.php" class="btn btn-danger">Close</a>
					</div>
			</form>
	</div>
	  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
		<script src="js/application.js"></script>
</body>
</html>

Since this program is called with application id as a parameter (for submitted or draft application), we checked if application id is available using $_REQUEST['id']. Then we select the application details from the database. Application status could be either Submitted or Draft or it could be a totally a new application. So, if application id is available, we know the application status. But if it is a new application, its status will be blank. Based on this, we show read-only values in the form for submitted status and editable values for draft status.

Write Ajax for Auto Save (application.js)

Auto saving of draft runs every 3 seconds. But it will save data only if there is any change in the form input. jQuery script is written in application.js.


$("#frm :input").change(function() {
   	$("#frm").data("changed",true);
});

The form state is changed when input data is changed in the form. This form state will be required while running auto save scripts.

There is a function named autoSave() and this function is called every 3 seconds using setInterval(). See the below code:


setInterval(function(){   // call autosave every 3 seconds
           autoSave();   
           }, 3000);

We are calling autoSave() as a callback function. Now let us see the code for autoSave() function.

Function autoSave()

This function takes the values from the form - name, email, age, gender and score. It will check if the form state has changed, then run Ajax to execute save_application.php. Note that, when a draft is saved, either a new application id is created for the first draft or an existing application id is available when a draft is saved again as draft. So that is why we will take application id as input from the form. For new application, application id is blank.


function autoSave()  {
	 var appl_id = $('#appl_id').val();  
	 var name 	= $('#name').val().trim(); 
	 var email 	= $('#email').val().trim(); 
	 var age 	= $('#age').val().trim(); 
	 var gender = $('#gender').val().trim(); 
	 var score 	= $('#score').val().trim();
	 if ($("#frm").data("changed")) { // if data is changed then only save
         $.ajax({  
                   url:"save_application.php",  
                   type:"POST",  
                   data:{appl_id:appl_id,name:name,email:email,age:age,gender:gender,score:score}, 
                   dataType:"text",  
                   success:function(response)  
                   {  
                      if(response == 'Error')  
                      {  
                      	$('#msgSave').html("Error");  
                      }
                      else {
	                    $('#appl_id').val(response);   
	                    $('#msgSave').html("Draft Saved");
	                	}
	                      setInterval(function(){  
	                           $('#msgSave').html('');  
	                      }, 3000);
	                      $("#frm").data("changed",false); //reset form state
                       }   
              	}); 
      }
	}

Below are the parameters for Ajax request.

  1. url: save_application.php - this will take the form values and insert/update into user_application table..
  2. type: "POST" - we are using post method.
  3. data: {appl_id:appl_id,name:name, email:email, age:age,gender:gender, score:score} - sending all the form input values.
  4. dataType: "text" - Response from Ajax call will be in text format.

If Ajax is successfully executed, we are checking the value of the response, i.e., output of save_application.php. If response is "Error", we display a message on the top of the form.

For successful saving of data, appl_id is the response. So, we are writing the appl_id in the form. Note that this appl_id could be a newly generated (for first draft) or it could be the same appl_id which was sent to Ajax call as request parameter to save_application.php (for saving draft more than once).

To display the message for few seconds, setInterval() is used. Form state is changed to false, as data is saved now.

Now, let's see the code of save_application.php. It simply takes the input values and inserts a new row in user_application table or update user_application table for the $appl_id. If $appli_id is blank, it will insert a row and if $appl_id has a value, it will update the existing row. Below is the code for save_application.php

save_application.php


<?php
include 'cfg/dbconnect.php';
$appl_id = $_POST['appl_id'];
$name = trim($_POST['name']);
$email = trim($_POST['email']);
$name = mysqli_real_escape_string($conn,$name);
$age = $_POST['age'];
$gender = $_POST['gender'];
$score = $_POST['score'];
$status = "Draft";
$curr_dt = date('Y-m-d');

if ($appl_id == "") { // insert
    $sql="insert into user_application (name, email, age, gender, percent_score, date,status)  values ('$name','$email','$age','$gender','$score','$curr_dt','$status')";
    $result=mysqli_query($conn,$sql);
    if ($result) {
      $appl_id = mysqli_insert_id($conn); // newly generated id
      echo $appl_id;
    }
    else echo "Error";
  }
else  // update
  {
   $sql = "update user_application set name='$name', email='$email', age='$age', gender='$gender', percent_score = '$score',date = '$curr_dt' where appl_id='$appl_id'";
   $result=mysqli_query($conn,$sql);
   if ($result) 
      echo $appl_id;  
    else echo "Error";
 }

Now, we will explain the step when application is submitted. It could be a direct submission or it could a draft application being submitted.

Process Application after Submit ( process_application.php)

User can submit the application first time after filling up the application form or user can edit a draft application and submit it.

process_application.php


<?php
if (isset($_POST['submit'])){
	$appl_id = $_POST['appl_id'];
	$name 	= trim($_POST['name']);
	$email 	= trim($_POST['email']);
	$name 	= mysqli_real_escape_string($conn,$name);
	$age 	= $_POST['age'];
	$gender = $_POST['gender'];
	$score 	= $_POST['score'];
	$curr_dt = date('Y-m-d');

	// do some validation
	if (!filter_var($email,FILTER_VALIDATE_EMAIL)){
		$email_err = "Invalid Email format";
		$err_flg = true;
	}
	else {  // check if email id already exists
		if($appl_id !="")  // existing draft application, same email id should not exists for other application
			$sql = "select * from user_application where email ='$email' and appl_id <> $appl_id";
		else
			$sql = "select * from user_application where email ='$email'";
		$rs = mysqli_query($conn,$sql);
		if (mysqli_num_rows($rs) > 0) {
			$email_err = "Email Id already exists";
			$err_flg = true;
		}
	}
	if($age <18 || $age >35){
		$age_err = "Age must be between 18 and 35";
		$err_flg = true;
	}
	if($score < 35 || $score > 100){
		$score_err = "Score percentage must be between 35  and 100";
		$err_flg = true;
	}

	if($appl_id != "")  { //  draft
			$prev_status = "Draft";
			$status = "Submitted";
		}
	else {
		$prev_status = "";
		$status = "Submitted";
	}
	
	if (!$err_flg) { 
		if($appl_id !="")  { // update draft
		    $update="update user_application set name='$name', email='$email', age='$age', gender='$gender', percent_score = '$score', date = '$curr_dt', status = '$status' where appl_id = '$appl_id'";
		    $result=mysqli_query($conn,$update);
	  	}
		else  {  // insert
		   $insert="insert into user_application (name, email, age, gender, percent_score, date, status)  values ('$name','$email','$age','$gender','$score','$curr_dt','$status')";
		   $result=mysqli_query($conn,$insert);
		   $appl_id = mysqli_insert_id($conn); // newly generated appl_id
		 }
		if ($result)
		  echo "<h4 style='text-align:center;color:green'>Your Application submitted successfully.";
		else {
			$status = $prev_status;
		  	echo "<h4 style='text-align:center;color:red;'>Could not submit your Application, Error occurred.<a href='index.php'> Application List</a></h4>";
		}
	}
	else 
		$status = $prev_status;
}

It takes the values from the form and does some basic validations. The application status after successful submission should be "Submitted", but if there is some error, we need to go back to the previous status. That is why we added the code in lines 37 to 44. If all validations are successful, we update the existing draft or insert a new application. If an error occurs or validation fails, we need to go back to previous status, so we added lines 59 and 64 ($status = $prev_status).

Add CSS (style.css)

Let us add below styles. We have already added style.css in index.php and application_form.php.

style.css


h2{
  margin-top: 20px;
}
h4{
  margin-top: 30px;
}
h2,h4{
	text-align: center;
}
.showMsg{
  width:auto;
  height: 20px;
  text-align: center;
}
#frm{
  width:40%;
  margin:auto;
}
label{
    font-weight: bold;
  }
table{
  width:100%;
}
table,th,td {
  margin:auto;
  border-collapse: collapse;
  border:1px solid #c4b2b2;
  }
thead {
  background-color: #265159;
  color:#fff;

}
thead,tbody {
  text-align: center;
}
textarea.form-control{
  resize:none;
  height: 100px;
}
.btn-default{
  background-color: #c5c5d5;
}
.appl{
  float: right;
  margin-bottom: 10px;
  }
.error{
  color:red;
}
@media (max-width: 600px){
#frm {
    width: 100%;
  }
}

save draft feature in formsTest the Application

Verify that Apache and MySQL services are running in XAMPP control panel. Run localhost/autosave in the browser. You will see the home page.

Click on New Application button and enter values, you will see while you are entering the values, a message appearing on top of the form saying "Draft Saved". Close the application. You will see your application is saved with status Draft.

save draft of a form in ajax in php

save form contents as draft in php and ajax

Use edit link to update the draft application and submit. Application should be submitted successfully and status will be "Submitted".

We have now completed the development and testing of the application. Hope you could understand all the steps and you could test it successfully.

save html form as draftImportant Note

  1. While saving the draft we have not used validation for email id, age and marks. But, during submission these are being validated. So, you can enter anything in these fields and draft will be saved. But while submitting you will see validation error messages.
  2. Instead of Auto Save, you can use a button like "Save as Draft", when user clicks on this button form data will be saved. Only difference will be instead of calling the autoSave function using setInterval(), just call the same function on onClick event of the button.

Download source code for Autosave using ajax in PHPDownload Source Code

Download the source code by clicking the download button below:

add save as draft in form dataConclusion

In this topic, we have seen how you can implement auto saving of the form using Ajax. We have used only a few fields in the form. This was just an example to show how it works. But in actual project you might see a data entry form with many fields in it. In that case Auto Save will be very useful for the users.