Learn to create a html table that your users can easily edit on the front end side of your web application. 

Your users can edit a whole row of your html table or just one cell just by clicking in a cell.

Below is a demo html table:

Demo Table
HTML Table Edits/Updates

All the changes will be displayed below

At first, it would appear to be plain regular html table. 

However, if you click on any of the columns (First name, last name or email), that cell will become editable. After you make any change to a cell and click out of it, the updated data will be shown under "HTML Table Edits/Updates".

Also, you can click the "Edit" link under the "Option" column and the whole row will become editable. And edit link will be replace with "Save | Cancel |". 

Let's dissect this whole editable process so you can use it in your own web projects.

Getting HTML Table Data

Let's assume that you got your table data via ajax call in jquery and it has the following array:

//ajax row data
	var ajax_data =
	[
		{fname:"Code", lname:"With Mark", email:"[email protected]"}, 
		{fname:"Mary", lname:"Moe", email:"[email protected]"},
		{fname:"John", lname:"Doe", email:"[email protected]"},
		{fname:"Julie", lname:"Dooley", email:"[email protected]"},
	]

Create HTML Table

Based on your ajax data, below code will create your table in jquery:

    var random_id = function  () 
	{
		var id_num = Math.random().toString(9).substr(2,3);
		var id_str = Math.random().toString(36).substr(2);
		
		return id_num + id_str;
	}


	//--->create data table > start
	var tbl = '';
	tbl +='<table class="table table-hover">'

		//--->create table header > start
		tbl +='<thead>';
			tbl +='<tr>';
			tbl +='<th>First Name</th>';
			tbl +='<th>Last Name</th>';
			tbl +='<th>Email</th>';
			tbl +='<th>Options</th>';
			tbl +='</tr>';
		tbl +='</thead>';
		//--->create table header > end

		
		//--->create table body > start
		tbl +='<tbody>';

			//--->create table body rows > start
			$.each(ajax_data, function(index, val) 
			{
				//you can replace with your database row id
				var row_id = random_id();

				//loop through ajax row data
				tbl +='<tr row_id="'+row_id+'">';
					tbl +='<td ><div class="row_data" edit_type="click" col_name="fname">'+val['fname']+'</div></td>';
					tbl +='<td ><div class="row_data" edit_type="click" col_name="lname">'+val['lname']+'</div></td>';
					tbl +='<td ><div class="row_data" edit_type="click" col_name="email">'+val['email']+'</div></td>';

					//--->edit options > start
					tbl +='<td>';
					 
						tbl +='<span class="btn_edit" > <a href="#" class="btn btn-link " row_id="'+row_id+'" > Edit</a> </span>';

						//only show this button if edit button is clicked
						tbl +='<span class="btn_save"> <a href="#" class="btn btn-link"  row_id="'+row_id+'"> Save</a> | </span>';
						tbl +='<span class="btn_cancel"> <a href="#" class="btn btn-link" row_id="'+row_id+'"> Cancel</a> | </span>';

					tbl +='</td>';
					//--->edit options > end
					
				tbl +='</tr>';
			});

			//--->create table body rows > end

		tbl +='</tbody>';
		//--->create table body > end

	tbl +='</table>'	
	//--->create data table > end

For the most part this is fairly easy to follow. 

The section you want to pay close attention to is in "each loop" because that's where the important stuff is:

//--->create table body rows > start
			$.each(ajax_data, function(index, val) 
			{
				//you can replace with your database row id
				var row_id = random_id();

				//loop through ajax row data
				tbl +='<tr row_id="'+row_id+'">';
					tbl +='<td ><div class="row_data" edit_type="click" col_name="fname">'+val['fname']+'</div></td>';
					tbl +='<td ><div class="row_data" edit_type="click" col_name="lname">'+val['lname']+'</div></td>';
					tbl +='<td ><div class="row_data" edit_type="click" col_name="email">'+val['email']+'</div></td>';

					//--->edit options > start
					tbl +='<td>';
					 
						tbl +='<span class="btn_edit" > <a href="#" class="btn btn-link " row_id="'+row_id+'" > Edit</a> </span>';

						//only show this button if edit button is clicked
						tbl +='<span class="btn_save"> <a href="#" class="btn btn-link"  row_id="'+row_id+'"> Save</a> | </span>';
						tbl +='<span class="btn_cancel"> <a href="#" class="btn btn-link" row_id="'+row_id+'"> Cancel</a> | </span>';

					tbl +='</td>';
					//--->edit options > end
					
				tbl +='</tr>';
			});

			//--->create table body rows > end

Here you will loop through all of your rows and assign custom attributes( edit_type="click" col_name="fname" ) and class "row_data" which you will use later on to manipulate your table data. 

Note: For row_id, I am using a random string code but you should replace that with your database row id.

Show HTML Table

Next you will print out your table to the DOM and hide buttons (save and cancel):

//out put table data
$(document).find('.tbl_user_data').html(tbl);

$(document).find('.btn_save').hide();
$(document).find('.btn_cancel').hide(); 

Make Your HTML Table Editable

Let's add a trigger when someone clicks in any of the cells(first or last name or email).

//--->make div editable > start
$(document).on('click', '.row_data', function(event) 
{
	event.preventDefault(); 

	if($(this).attr('edit_type') == 'button')
	{
		return false; 
	}

	//make div editable
	$(this).closest('div').attr('contenteditable', 'true');
	//add bg css
	$(this).addClass('bg-warning').css('padding','5px');

	$(this).focus();
})	
//--->make div editable > end

Here a html5 attribute call contenteditable was added. This is used by most of the browsers out there. You can see the compatibility chart on caniuse - contenteditable

Just a side not, in my experience, it's best to use this attribute with "div or span" to ensure it will work as expected. 

Next, a bootstrap background class(bg-warning) was added to make it standout. Also, a padding to 5px was added. Finally, focus was set to that cell. 

Make Whole Table Row Editable

//--->button > edit > start	
$(document).on('click', '.btn_edit', function(event) 
{
	event.preventDefault();
	var tbl_row = $(this).closest('tr');

	var row_id = tbl_row.attr('row_id');

	tbl_row.find('.btn_save').show();
	tbl_row.find('.btn_cancel').show();

	//hide edit button
	tbl_row.find('.btn_edit').hide(); 

	//make the whole row editable
	tbl_row.find('.row_data')
	.attr('contenteditable', 'true')
	.attr('edit_type', 'button')
	.addClass('bg-warning')
	.css('padding','3px')

	//--->add the original entry > start
	tbl_row.find('.row_data').each(function(index, val) 
	{  
		//this will help in case user decided to click on cancel button
		$(this).attr('original_entry', $(this).html());
	}); 		
	//--->add the original entry > end

});
//--->button > edit > end

First, the closest "tr" was obtained based the edit link of the row. And from that "tr" the "row_id" was obtained. Next, "save and cancel" buttons were shown and "edit" was hidden. 

Also, an attribute of "contenteditable" was added and "edit_type" was changed from "click" to "button". Follow by bootstrap background class(bg-warning) and padding of 3px was added. 

Finally, each loop was ran for all the cells (first and last name, and email) with the class of "row_data" and their values were added to attribute "original_entry". This was done in case if users edited a cell but later on changed their mind and clicked on "cancel link".

Cancel User Table Data Entry

 //--->button > cancel > start	
$(document).on('click', '.btn_cancel', function(event) 
{
	event.preventDefault();

	var tbl_row = $(this).closest('tr');

	var row_id = tbl_row.attr('row_id');

	//hide save and cacel buttons
	tbl_row.find('.btn_save').hide();
	tbl_row.find('.btn_cancel').hide();

	//show edit button
	tbl_row.find('.btn_edit').show();

	//make the whole row editable
	tbl_row.find('.row_data')
	.attr('edit_type', 'click')
	.removeAttr('contenteditable')
	.removeClass('bg-warning')
	.css('padding','') 

	tbl_row.find('.row_data').each(function(index, val) 
	{   
		$(this).html( $(this).attr('original_entry') ); 
	});  
});
//--->button > cancel > end

First, the closest "tr" was obtained based the cancel link of the row. And from that "tr" the "row_id" was obtained. Next, "save and cancel" buttons were hidden and "edit" was shown. 

Also, attribute "edit_type" was changed from "button" to "click". The  attribute(contenteditable) was removed and class(bg-warning) was removed and padding was set to null.

Finally, each loop was ran for all the cells (first and last name, and email) with the class of "row_data" and their values were reset from attribute "original_entry". 

Save Whole Table Row Entry Data


//--->save whole row entery > start	
$(document).on('click', '.btn_save', function(event) 
{
	event.preventDefault();
	var tbl_row = $(this).closest('tr');

	var row_id = tbl_row.attr('row_id');

	
	//hide save and cacel buttons
	tbl_row.find('.btn_save').hide();
	tbl_row.find('.btn_cancel').hide();

	//show edit button
	tbl_row.find('.btn_edit').show();


	//make the whole row editable
	tbl_row.find('.row_data')
	.attr('edit_type', 'click')
	.removeAttr('contenteditable')
	.removeClass('bg-warning')
	.css('padding','') 

	//--->get row data > start
	var arr = {}; 
	tbl_row.find('.row_data').each(function(index, val) 
	{   
		var col_name = $(this).attr('col_name');  
		var col_val  =  $(this).html();
		arr[col_name] = col_val;
	});
	//--->get row data > end

	//use the "arr"	object for your ajax call
	$.extend(arr, {row_id:row_id});

	//out put to show
	$('.post_msg').html( '<pre class="bg-success">'+JSON.stringify(arr, null, 2) +'</pre>')
	 

});
//--->save whole row entery > end

First, the closest "tr" was obtained based the cancel link of the row. And from that "tr" the "row_id" was obtained. Next, "save and cancel" buttons were hidden and "edit" was shown. 

Also, attribute "edit_type" was changed from "button" to "click". The  attribute(contenteditable) was removed and class(bg-warning) was removed and padding was set to null.

Finally, each loop was ran for all the cells (first and last name, and email) with the class of "row_data" and their values were append to an object array. After the each loop, row_id object was append to "arr". 

I am just outputting to show you the changes but you can easily take the "arr" object and send it to your server to process it. 

Save Single HTML Table Cell Data

//--->save single field data > start
$(document).on('focusout', '.row_data', function(event) 
{
	event.preventDefault();

	if($(this).attr('edit_type') == 'button')
	{
		return false; 
	}

	var row_id = $(this).closest('tr').attr('row_id'); 
	
	var row_div = $(this)
	.removeAttr('contenteditable') //make div editable		
	.removeClass('bg-warning') //add bg css
	.css('padding','')

	var col_name = row_div.attr('col_name'); 
	var col_val = row_div.html(); 

	var arr = {};
	arr[col_name] = col_val;

	//use the "arr"	object for your ajax call
	$.extend(arr, {row_id:row_id});

	//out put to show
	$('.post_msg').html( '<pre class="bg-success">'+JSON.stringify(arr, null, 2) +'</pre>');
	
})	
//--->save single field data > end

First, it will check to see if "edit_type" is "button" or not. If it is, then it will return false and die. If it is not, then it will continue.

Next, the closest "tr" was obtained based the cancel link of the row. And from that "tr" the "row_id" was obtained. 

Also, attribute "edit_type" was changed from "button" to "click". The  attribute(contenteditable) was removed and class(bg-warning) was removed and padding was set to null.

Finally, the field name and value is obtained and put in object "arr". After that, row_id object was append to "arr". 

I am just outputting to show you the changes but you can easily take the "arr" object and send it to your server to process it. 

Demo Again For You

To make it easier for you to try it out again.

Demo
HTML Table Edits/Upates

All the changes will be displayed below

Whole Demo Code

Everything you will need to include it in your project:

 
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
 


<script type="text/javascript">
$(document).ready(function($)
{
	//ajax row data
	var ajax_data =
	[
		{fname:"Code", lname:"With Mark", email:"[email protected]"}, 
		{fname:"Mary", lname:"Moe", email:"[email protected]"},
		{fname:"John", lname:"Doe", email:"[email protected]"},
		{fname:"Julie", lname:"Dooley", email:"[email protected]"},
	]



	var random_id = function  () 
	{
		var id_num = Math.random().toString(9).substr(2,3);
		var id_str = Math.random().toString(36).substr(2);
		
		return id_num + id_str;
	}


	//--->create data table > start
	var tbl = '';
	tbl +='<table class="table table-hover">'

		//--->create table header > start
		tbl +='<thead>';
			tbl +='<tr>';
			tbl +='<th>First Name</th>';
			tbl +='<th>Last Name</th>';
			tbl +='<th>Email</th>';
			tbl +='<th>Options</th>';
			tbl +='</tr>';
		tbl +='</thead>';
		//--->create table header > end

		
		//--->create table body > start
		tbl +='<tbody>';

			//--->create table body rows > start
			$.each(ajax_data, function(index, val) 
			{
				//you can replace with your database row id
				var row_id = random_id();

				//loop through ajax row data
				tbl +='<tr row_id="'+row_id+'">';
					tbl +='<td ><div class="row_data" edit_type="click" col_name="fname">'+val['fname']+'</div></td>';
					tbl +='<td ><div class="row_data" edit_type="click" col_name="lname">'+val['lname']+'</div></td>';
					tbl +='<td ><div class="row_data" edit_type="click" col_name="email">'+val['email']+'</div></td>';

					//--->edit options > start
					tbl +='<td>';
					 
						tbl +='<span class="btn_edit" > <a href="#" class="btn btn-link " row_id="'+row_id+'" > Edit</a> </span>';

						//only show this button if edit button is clicked
						tbl +='<span class="btn_save"> <a href="#" class="btn btn-link"  row_id="'+row_id+'"> Save</a> | </span>';
						tbl +='<span class="btn_cancel"> <a href="#" class="btn btn-link" row_id="'+row_id+'"> Cancel</a> | </span>';

					tbl +='</td>';
					//--->edit options > end
					
				tbl +='</tr>';
			});

			//--->create table body rows > end

		tbl +='</tbody>';
		//--->create table body > end

	tbl +='</table>'	
	//--->create data table > end

	//out put table data
	$(document).find('.tbl_user_data').html(tbl);

	$(document).find('.btn_save').hide();
	$(document).find('.btn_cancel').hide(); 


	//--->make div editable > start
	$(document).on('click', '.row_data', function(event) 
	{
		event.preventDefault(); 

		if($(this).attr('edit_type') == 'button')
		{
			return false; 
		}

		//make div editable
		$(this).closest('div').attr('contenteditable', 'true');
		//add bg css
		$(this).addClass('bg-warning').css('padding','5px');

		$(this).focus();
	})	
	//--->make div editable > end


	//--->save single field data > start
	$(document).on('focusout', '.row_data', function(event) 
	{
		event.preventDefault();

		if($(this).attr('edit_type') == 'button')
		{
			return false; 
		}

		var row_id = $(this).closest('tr').attr('row_id'); 
		
		var row_div = $(this)
		.removeAttr('contenteditable') //make div editable		
		.removeClass('bg-warning') //add bg css
		.css('padding','')

		var col_name = row_div.attr('col_name'); 
		var col_val = row_div.html(); 

		var arr = {};
		arr[col_name] = col_val;

		//use the "arr"	object for your ajax call
		$.extend(arr, {row_id:row_id});

		//out put to show
		$('.post_msg').html( '<pre class="bg-success">'+JSON.stringify(arr, null, 2) +'</pre>');
		
	})	
	//--->save single field data > end

 
	//--->button > edit > start	
	$(document).on('click', '.btn_edit', function(event) 
	{
		event.preventDefault();
		var tbl_row = $(this).closest('tr');

		var row_id = tbl_row.attr('row_id');

		tbl_row.find('.btn_save').show();
		tbl_row.find('.btn_cancel').show();

		//hide edit button
		tbl_row.find('.btn_edit').hide(); 

		//make the whole row editable
		tbl_row.find('.row_data')
		.attr('contenteditable', 'true')
		.attr('edit_type', 'button')
		.addClass('bg-warning')
		.css('padding','3px')

		//--->add the original entry > start
		tbl_row.find('.row_data').each(function(index, val) 
		{  
			//this will help in case user decided to click on cancel button
			$(this).attr('original_entry', $(this).html());
		}); 		
		//--->add the original entry > end

	});
	//--->button > edit > end


	//--->button > cancel > start	
	$(document).on('click', '.btn_cancel', function(event) 
	{
		event.preventDefault();

		var tbl_row = $(this).closest('tr');

		var row_id = tbl_row.attr('row_id');

		//hide save and cacel buttons
		tbl_row.find('.btn_save').hide();
		tbl_row.find('.btn_cancel').hide();

		//show edit button
		tbl_row.find('.btn_edit').show();

		//make the whole row editable
		tbl_row.find('.row_data')
		.attr('edit_type', 'click')
		.removeAttr('contenteditable')
		.removeClass('bg-warning')
		.css('padding','') 

		tbl_row.find('.row_data').each(function(index, val) 
		{   
			$(this).html( $(this).attr('original_entry') ); 
		});  
	});
	//--->button > cancel > end

	
	//--->save whole row entery > start	
	$(document).on('click', '.btn_save', function(event) 
	{
		event.preventDefault();
		var tbl_row = $(this).closest('tr');

		var row_id = tbl_row.attr('row_id');

		
		//hide save and cacel buttons
		tbl_row.find('.btn_save').hide();
		tbl_row.find('.btn_cancel').hide();

		//show edit button
		tbl_row.find('.btn_edit').show();


		//make the whole row editable
		tbl_row.find('.row_data')
		.attr('edit_type', 'click')
		.removeAttr('contenteditable')
		.removeClass('bg-warning')
		.css('padding','') 

		//--->get row data > start
		var arr = {}; 
		tbl_row.find('.row_data').each(function(index, val) 
		{   
			var col_name = $(this).attr('col_name');  
			var col_val  =  $(this).html();
			arr[col_name] = col_val;
		});
		//--->get row data > end

		//use the "arr"	object for your ajax call
		$.extend(arr, {row_id:row_id});

		//out put to show
		$('.post_msg').html( '<pre class="bg-success">'+JSON.stringify(arr, null, 2) +'</pre>')
		 

	});
	//--->save whole row entery > end


}); 
</script>

 

<div class="panel panel-default">
  <div class="panel-heading"><b> Demo </b> </div>

  <div class="panel-body">
	
	<div class="tbl_user_data"></div>

  </div>

</div>

 

<div class="panel panel-default">
  <div class="panel-heading"><b>HTML Table Edits/Upates</b> </div>

  <div class="panel-body">
	
	<p>All the changes will be displayed below</p>
	<div class="post_msg"> </div>

  </div>
</div>










Name

Email

Website

Comment

Post Comment