Nick Price
Nick Price

Reputation: 963

jQuery - reusing code without duplicating it

I have a page that is essentially a table which has its rows duplicated when the button is pushed. Each additional row has a unique id/name.

I now have this problem. I essentially have a similar table on a different page. Main difference is that it may have additional inputs. At the moment, it looks something like this:

JavaScript

 var cloned;

 $(function() {
   initDatepickersAndSelect();

   $('#add_row').on('click', function(evt) {
     addRow();
   });
   $('#delete_row').on('click', function(evt) {
     deleteRow();
   });

   $('#add_row2').on('click', function(evt) {
     addRow(x);
   });
   $('#delete_row2').on('click', function(evt) {
     deleteRow(x);
   });
 });

 function initDatepickersAndSelect() {
   cloned = $("table tr#actionRow0").eq(0).clone();
   $(".dateControl").datepicker({
     dateFormat: "dd-mm-yy"
   });

   $(".responsibility").select2({
     tags: true
   });

   $(".campaignType").select2({
     tags: true
   });
 }

 function addRow() {

   var $tr = cloned.clone();
   var newRowIdx = $("table#actionTable tr").length - 1;
   $tr.attr('id', 'actionRow' + newRowIdx);

   $tr.find("input, select").each(function(i_idx, i_elem) {
     var $input = $(i_elem);

     if ($input.is("input")) {
       $input.val("");
     }

     $input.attr({
       'id': function(_, id) {
         return id + newRowIdx;
       },
       'name': function(_, name) {
         return name.replace('[0]', '[' + newRowIdx + ']');
       },
       'value': ''
     });

   });
   $tr.appendTo("table#actionTable");

   $(".dateControl", $tr).datepicker({
     dateFormat: "dd-mm-yy"
   });

   $(".responsibility", $tr).select2({
     tags: true
   });

   $(".campaignType", $tr).select2({
     tags: true
   });
 }

 function deleteRow() {
   var curRowIdx = $("table#actionTable tr").length;
   if (curRowIdx > 2) {
     $("#actionRow" + (curRowIdx - 2)).remove();
     curRowIdx--;
   }
 }

HTML

<div class="col-md-12 noPadding">
  <table class="table table-bordered table-hover additionalMargin" id="reportTable">
    <thead>
      <tr>
        <th class="text-center">Something</th>
        <th class="text-center">Something else</th>
      </tr>
    </thead>
    <tbody>
      <tr id='actionRow0'>
        <td>
          <select class="campType" name='reportInput[0][campType]' id="reportInput">
            <option value=""></option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
            <option value="4">4</option>
          </select>
        </td>
        <td>
          <input type="text" name='reportInput[0][campDelivery]' id="dateInput" class="form-control" />
        </td>
      </tr>
    </tbody>
  </table>
  <a id="add_row" class="btn btn-default pull-right">Add Row</a>
  <a id='delete_row' class="pull-right btn btn-default">Delete Row</a>
</div>

The last thing I want to do is duplicate all of my JavaScript and rename things to match the above.

What I am wondering, is there anyway I could reuse the JavaScript?

Any advice appreciated.

Thanks

(code also available as JSFiddle)

Upvotes: 0

Views: 206

Answers (3)

Sascha
Sascha

Reputation: 1156

You may just clone a row and reset attibutes within with something like:

function addRow(id) {
  var c = $("table#"+id+" tr").last();
  $("table#"+id+" tbody").append(c.clone().attr({id: "addedrow" + Math.random()*10+1}));
}

function deleteRow(id,index) {
  var curRowIdx = $("table#"+id+" tr").length;
  if (curRowIdx > 2) {
    if(index != void 0) {
      $("table#"+id+" tr")[index].remove();
    }else{
      $("table#"+id+" tr").last().remove();
    }        
  }
}

Call it with

$('#add_row').on('click', function(evt){addRow("reportTable");});
$('#delete_row').on('click', function(evt){deleteRow("reportTable",1);});

Maybe you'll prepare new rows for your table with something like

var emptyRow[id] = $("table#"+id+" tr").last();

and change

$("table#"+id+" tbody").append(c.clone().attr({id: "addedrow" + Math.random()*10+1}));

to

$("table#"+id+" tbody").append(emptyRow[id].clone().attr({id: "addedrow" + Math.random()*10+1}));

Upvotes: 1

Sam Watkins
Sam Watkins

Reputation: 8309

I suggest to have an invisible "template row" in your table, which you can copy to add new rows.

Something like this:

<style>
tr.template { display: none; }
</style>

<table id="table1">
<tr class="template"><td><input id="blah">/td><td><input id="foo"></td></tr>
</table>

<button id="add">Add Row</button>

<script>
function add_row($table) {
    var count = $table.find('tr').length - 1;
    var tr_id = ""+(count+1);
    var $template = $table.find('tr.template');
    var $tr = $template.clone().removeClass('template').prop('id', tr_id);
    $tr.find(':input').each(function() {
        var input_id = $(this).prop('id');
        input_id = tr_id + '_' + input_id;
        $(this).prop('id', input_id);
    });
    $table.find('tbody').append($tr);
}
$('#add').on('click', function() { add_row($('#table1')); });
</script>

I think it will be easier to make the code generic in this way. If you don't want the inputs in the template to be submitted, you can disable them or remove them somehow.

Demo: http://sam.nipl.net/table-demo.html

Upvotes: 1

sg.cc
sg.cc

Reputation: 1816

Based on my understanding of the question, I think you could do something like this. Assuming a function called addRow as seen in your fiddle, the first step is to include that JS on all pages where you want that functionality. You then mentioned that other pages might have additional controls. For this, I'd override the function...

On the page with normal controls

function addRow() {
  // Row adding code...
}

On the page with extra controls

var oldAddRow = addRow;
var addRow = function(){
  $('.some_other_control').click(ctrlHandler);
  $('.some .input').val('');
  oldAddRow();
}

Upvotes: 1

Related Questions