Thursday, April 25, 2013

Creating Dynamic Table Rows and Columns In Javascript

Before we get into the solution, here I first discuss the problem we are going to solve through Javascirpt.

Problem : We have a HTML page which looks like this:

  



 



The coresponding HTML is also given below.

<html>
<body>
<table id="table"></table>
<input type='button' value='Add New' id='button' onclick='add_new()'>
</body>
</html>


Now when we click on "Add New" button, a new row is created and appended to the <table> element shown in the above HTML. If we repeat it couple of times, we would be generating a big dynamically generated table as shown in the picture below ...


The "Click Me" button, when clicked,  shows a message with the coresponding row number as shown in the picture below.




The "Remove Me" buttons delete the corresponding row. And if we remove couple of rows the page becomes like this ..




The above scenario would involve dynamic creation of table rows (tr) and cells (td) in Javascript. Let me put the solution below and then we would dissect each part of the code. Check the Full HTML and Javascript code below.

<html>
<head>
<script type='text/javascript'>
   
//// When ClickkMe button is clicked   
function checkMe(id)
{
   alert("I am Row : " + id);
}
   
// Remove any Row from the Table
function removeMe(id)
{

  // Get the Table
  var t = document.getElementById('table');
 
  // Delete the Selected Row
  t.deleteRow(id);
 
  // Re-Index the Rows Heading
  for(var j=0;j<t.rows.length; j++)
  {
     /// Index Row Numbers
     var tr = t.rows[j];
    

     // FOR IE
     if(tr.children[0].innerText)
        tr.children[0].innerText = "Row : " + j;
     // FOR Others 
     else if(tr.children[0].textContent)
        tr.children[0].textContent = "Row : " + j; 
  }
 
  /// GET all CLICK ME buttons
  var p = document.getElementsByName('button_click');
 
  /// We need to re-define the onclick behaviour of these buttons
  /// checkMe() takes corresponding row number to show the message
  for(var j=0; j<p.length; j++)
  {
    p[j].setAttribute("onclick", "checkMe("+j+")");
  }
 
  /// GET all REMOVE ME buttons
  var p = document.getElementsByName('button_remove');
 
  /// We need to re-define the onclick behaviour of these buttons
  /// removeMe() takes corresponding row number to delete
  for(var j=0; j<p.length; j++)
  {
    p[j].setAttribute("onclick", "removeMe("+j+")");
  }

}

// Addition of a new row at the end of the Table
function add_new()
{
  // GET The Table
  var t = document.getElementById('table');
 
  // GET row count
  var lastrow = t.rows.length;
 
  // Insert Row at the End
  var row = t.insertRow(lastrow);

  // leftmost Cell showing Row No :
  var cellLeft = row.insertCell(0);
  var textNode = document.createTextNode("Row : " + lastrow);
  cellLeft.appendChild(textNode);

  // Next Cell/TD for Input Element
  cellLeft = row.insertCell(1);
  var i = document.createElement('input');
  i.setAttribute('type','text');
  i.setAttribute('value',lastrow);
  i.setAttribute('name','text'+lastrow);
  cellLeft.appendChild(i);

  // Next Cell/TD for 'Click ME' button
  cellLeft = row.insertCell(2);
  i = document.createElement('input');
  i.setAttribute('type','button');
  i.setAttribute('name','button_click');
  i.setAttribute('value','Click Me');
  i.setAttribute('onclick','checkMe('+lastrow+')');
  cellLeft.appendChild(i);

  // Next cell/TD for 'Remove Me' button
  cellLeft = row.insertCell(3);
  i = document.createElement('input');
  i.setAttribute('type','button');
  i.setAttribute('name','button_remove');
  i.setAttribute('value','Remove Me');
 
  /// We define the onclick behaviour of each remove button
  i.setAttribute('onclick','removeMe('+lastrow+')');
  cellLeft.appendChild(i);

}
</script>
</head>
<body>
<table id="table"></table>
<input type='button' value='Add New' id='button' onclick='add_new()'>
</body>
</html>


Explanation ::

a. The add_new() function does a lot of job when we click the "Add New" button.
    

    1. First we reach to the table through getElementById('table') method, then we use insertRow() method to insert a new row at the position specified by lastrow. The lastrow variable holds last row's position as t.rows.length returns the total number of rows in the table. The last row created is returned in variable row.
   

   2. Now, add a new cell to the row where the text "Row : 0" would appear. The first row starts from index zero in our example. Then we create cells in that row starting form index 0. The method insertCell(0) created first cell, insertCell(1) creates second cell (td element) etc. in that row.
   

   3. For the fist cell, we create only a text node with document.createTextNode() method. After we create a node, we must append it to the cell associated with it. The statment cellLeft.appendChild(textNode); does it.
   

   4. The next cell at position 1, which was created with row.insertCell(1) is going to have an Input field which would also show Row Number. For creating any element within the HTML, we need to use document.createElement() method with element type as argument. Hence document.createElement('input') creates an input element but does not append it to the cell associated with it. Until and unless we do so ( append the input element to a <td> cell  by calling appendChild() ), it does not get rendered by the browser. Next, we add some attributes to the input element by setAttibute() method.
   

    The statement setAttribute('name','text'+lastrow); would add "name" property to that input element and assign "text0" or "text1" etc. value to that property. We would not see any effect of adding & setting the 'name' property of that text input element here, but this might be useful if we want to submit the form including the table above with some required input.
   

   5. Then we again call the appendChild() method to append the new input element to the parent cell or <td> element.
   

   6. Similarly, we create two more input element (type button) and append them to their associated cells.
   

       The following statement :
      i.setAttribute('onclick','checkMe('+lastrow+')');
      gives the input element a property like "onclick = 'checkMe(1)'".
     
       The statement :
      i.setAttribute('onclick','removeMe('+lastrow+')');
      gives the last input element a property like "onclick = 'removeMe(1)'".

      The removeMe() function actually removes the row which is passed to it as a parameter.

b. The removeMe() function is called when "Remove Me" button corresponding to any row is clicked. This function deletes the row. 

   
  For example :
   removeMe(2);
   would delete the row number 2 (the third row from top). Row number 0 would refer to the first row from the top.
  
   We use
   t.deleteRow(id); // id is the row index,
   to delete any particular row. 


It works like an array. If a table has 4 rows [ index 0,1,2,3 ] and we delete any row from this array it becomes [ index 0,1,2 ]. Again if we delete a row, it becomes [ index 0,1 ]. Deleting rows would involve some critical situation. Suppose, there are 4 rows with index 0,1,2,3 with remove button's onclick events are shown below :
   

   1st row's [index 0] "Remove Me" button's onclick event -- removeMe(0)
   2nd row's [index 1] "Remove Me" button's onclick event -- removeMe(1)
   3rd row's [index 2] "Remove Me" button's onclick event -- removeMe(2)
   4th row's [index 3] "Remove Me" button's onclick event -- removeMe(3)

   Now when we delete 2nd row [index 1] by calling removeMe(1), the row indexes become 0,1,2 as it works more like an array. But the all the "Remove Me" button's onclick events remain as shown below ...
   

   1st row's [index 0] "Remove Me" button's onclick event -- removeMe(0)
   3rd row's [index 1] "Remove Me" button's onclick event -- removeMe(2)
   4th row's [index 2] "Remove Me" button's onclick event -- removeMe(3)

   The row indexes are updated within the table while the function calls are not updated. At this situation, if we try to call the last row's removeMe(3) function, this would generate an error as index 3 is not available. Table row indexes are 0,1,2 now. The following code gets all the remove buttons in variable p, and then we change the onclick property.

   var p = document.getElementsByName('button_remove');
 for(var j=0; j<p.length; j++)
 {
     p[j].setAttribute("onclick", "removeMe("+j+")");
 }


   Similar treatment we do with all "Click Me" buttons and text heading at cell zero in each row of the table. For putting a text content inside a span or td tag, we use "innerText" for IE and "textContent" functions for other browsers.


This way, we dynamically add/delete rows to HTML table through JavaScript.

2 comments:

Anonymous said...

Hey brilliant tute man, thx

Anonymous said...

give me a download link to download this code