-1

Following is the code to generate a table with input fields and buttons.

 <table id="myTable">
    <tr>
        <td><input type="text" class="text1"></td>
        <td><input type="text" class="text2"></td>
        <td><input type="text" class="text3"></td>
        <td class="up"><button type="button" class="append_up">Up</button></td>
        <td class="down"><button type="button" class="append_down">Down</button></td>
    </tr>
    <tr>
        <td><input type="text" class="text1"></td>
        <td><input type="text" class="text2"></td>
        <td><input type="text" class="text3"></td>
        <td class="up"><button type="button" class="append_up">Up</button></td>
        <td class="down"><button type="button" class="append_down">Down</button></td>
    </tr>
    <tr>
        <td><input type="text" class="text1"></td>
        <td><input type="text" class="text2"></td>
        <td><input type="text" class="text3"></td>
        <td class="up"><button type="button" class="append_up">Up</button></td>
        <td class="down"><button type="button" class="append_down">Down</button></td>
    </tr>
</table>

I want to be able to append a similar row anywhere in the table using JavaScript. If I click the Up button I want a similar row to be appended just above that row, and if clicked down, just below that row. And finally I want to be able to get all the data from the table in the order as created by clicking the buttons. Please help.

After receiving few answers this is what i did.

$(document).ready(function(){
          var html = '<tr><td><input type="text" class="text1"></td><td><input type="text" class="text2"></td><td><input type="text" class="text3"></td><td><button type="button" class="append_up">Up</button></td><td><button type="button" class="append_down">Down</button></td></tr>';

          $('.append_up').click(function(e) {
              e.preventDefault();
              $(this).closest('tr').before(html);
          });

          $('.append_down').click(function(e) {
              e.preventDefault();
              $(this).closest('tr').after(html);
          });

      }); 

I was able to append rows but clicking on the button from the new row does nothing.

XperSona
  • 25
  • 11

4 Answers4

2

As I failed to find a duplicate containing an answer to my liking (as in... works even in IE6... and doesn't need a trunk-load of work-arounds like copying events etc..) I'll post mine in pure javascript here (explained in comments):

<table id="tst_table"><tbody>
  <tr>
    <td><input type="text" class="text1"></td>
    <td><input type="text" class="text2"></td>
    <td><input type="text" class="text3"></td>
    <td><button type="button" class="append_up">Up</button></td>
    <td><button type="button" class="append_down">Down</button></td>
  </tr>
  <tr>
    <td><input type="text" class="text1"></td>
    <td><input type="text" class="text2"></td>
    <td><input type="text" class="text3"></td>
    <td><button type="button" class="append_up">Up</button></td>
    <td><button type="button" class="append_down">Down</button></td>
  </tr>
  <tr>
    <td><input type="text" class="text1"></td>
    <td><input type="text" class="text2"></td>
    <td><input type="text" class="text3"></td>
    <td><button type="button" class="append_up">Up</button></td>
    <td><button type="button" class="append_down">Down</button></td>
  </tr>
</tbody></table>

<script>  //hook it any way you like, this is just for focussing on the example..
document.getElementById('tst_table').onclick=(function(){
  function _addRow(trg, dir){ //private function to add row in any direction
    var row= trg.parentNode.parentNode            //get correct row
    , clone= row.cloneNode(true)                  //deep-clone that row
    , inpts= clone.getElementsByTagName('input')  //get inputs in clone
    ,     L= inpts.length                         //total no of inputs in clone
    ; //end var
    for(;L--; inpts[L].value=inpts[L].defaultValue); //reset inputs to defaultValue
    row.parentNode.insertBefore(clone, dir ? row.nextSibling : row); //add row
    row=clone=inpts=L=null; //cleanup
  }
  return function(e){ //return uniform click-handler for the whole table
    var trg=e ? e.target : window.event.srcElement;    // get source element
    if(trg.nodeType === 3) trg = trg.parentNode;       // fix Safari bug
    var clsnam=' '+trg.className+' '; // get className, allow multiple classnames
    if(~clsnam.indexOf( ' append_up ' )) return _addRow(trg, 0);
    if(~clsnam.indexOf(' append_down ')) return _addRow(trg, 1);
  };
})();
</script>

One of the nice things is that this sets just one eventhandler for the table instead of a (new) function for every button.
In the table's onclick-handler (the returned function) you can handle any click-event that originated in the table: in this example it handles buttons whose class contains 'append_up' or 'append_down' (so you can also set other styling classes like <button class="red_rounded_button append_up">).
In some way's this is simpler/unobtrusive because it deep-copies a row (instead of needing some html-string, which (without jQuery) has some problems with tables in older browsers, notably IE).
Also note that this technique does not touch javascript's global name-space. EDIT: improved class-name cache so we don't get a misfire on (for example): alt_append_up and added early return.

Finally, to answer your last request: since this uses proper DOM-methods, every time you get the table's rows (and containing elements like inputs) you'll get them in order they are in the DOM (just what you wanted). Nice!

GitaarLAB
  • 14,536
  • 11
  • 60
  • 80
  • Simply ask me what you don't understand and I'll explain it. – GitaarLAB Nov 24 '14 at 09:53
  • Can you please tell me which the right way is; yours or the one Kiran P gave. Because that’s much simpler and easy to understand. And both seem to work fine. I cannot differentiate – XperSona Nov 24 '14 at 09:57
  • As you have already seen, it already solves some problems you have encountered in some other answers while solving some problems you didn't already think about (like the multiple class support and default-value support). However, the code is not universal (neither would other answers be) because you'd always have your own special requirements! There are 'universal' things that try to copy every possible thing, but then you'd ask how to over-ride some of those things. So you're either taming a jumbo jet or upgrading (to your needs) a Cessna.. (and you asked for javascript `:)`) – GitaarLAB Nov 24 '14 at 10:10
  • Try it for your self.. add one column to your table. This still works. Add a (default)`value` to your input-elements in the table.. This still works. In fact.. why ship three identical rows in your html... just ship one row, clone 2 below them on page-load.. – GitaarLAB Nov 24 '14 at 10:22
  • Important update: there was an error in my previous answer: `row=clone=inpts=l=null; //cleanup` should be `row=clone=inpts=L=null; //cleanup` (note capital `L`) (you could also leave that off (`row=clone=inpts=null;`), it's just an int that should be garbage collected, the cleanup is to try help the garbage collector with the actual DOM elements). Also I improved the class-name handling (by wrapping the full element's classname(s) in two spaces (thus insuring we don't get a mis-fire on (for example) ` – GitaarLAB Nov 24 '14 at 13:55
1
$('.append_up').click(function(){

   var str='<tr><td><input type="text" class="text1" value="vikram"></td><td><input type="text" class="text2"></td><td><input type="text" class="text3"></td><td><button type="button" class="append_up">Up</button></td><td><button type="button" class="append_down">Down</button></td></tr>';     
   $(this).parent().parent().before(str);
});
$('.append_down').click(function(){
   var str='<tr><td><input type="text" class="text1" value="sharma"></td><td><input type="text" class="text2"></td><td><input type="text" class="text3"></td><td><button type="button" class="append_up">Up</button></td><td><button type="button" class="append_down">Down</button></td></tr>';
   $(this).parent().parent().after(str);
});
Sharma Vikram
  • 2,440
  • 6
  • 23
  • 46
1
 var html = '<tr><td><input type="text" class="text1"></td><td><input type="text" class="text2"></td><td><input type="text" class="text3"></td><td><button type="button" class="append_up">Up</button></td><td><button type="button" class="append_down">Down</button></td></tr>';

$(document).ready(function(){
        $(document.body).on('click','.append_up',addAbove);
        $(document.body).on('click','.append_down',addBelow);


    });
    function addAbove()
    {
            $(this).closest('tr').before(html);
    }

    function addBelow()
    {
            $(this).closest('tr').after(html);
    }

    you are dynamically appending the elements and hence you should use and on method to bind the click. hope this helps.
Kiran P
  • 299
  • 2
  • 11
0

Try something like this:

$(document).ready(function(){
    var html = '<tr><td><input type="text" class="text1"></td><td><input type="text" class="text2"></td><td><input type="text" class="text3"></td><td><button type="button" class="append_up">Up</button></td><td><button type="button" class="append_down">Down</button></td></tr>';

    $('.append_up').click(function(e) {
        e.preventDefault();
        $(this).closest('tr').before(html);
    });

    $('.append_down').click(function(e) {
        e.preventDefault();
        $(this).closest('tr').after(html);
    });

});

There is a fiddle here: http://jsfiddle.net/vyfhrfvf/

madsobel
  • 2,797
  • 3
  • 14
  • 22