0

I have a problem with javascript on click. I have to add some input box when I press add more button but it didn't work.

Javascript

var i = $('table tr').length;
var count = $('table tr').length;
var row = i;
var a = 0;

for (a = 0; a <= i; a++) {
  $(".addmore_" + a).on('click', function() {
    var data = "<input class='form-control' type='text' id='packinglist_" + a + "' name='packinglist[]'/>";
    $("#keatas_" + a).append(data);
  });
};

HTML

for ($i = 1; $i <= 5; $i++) {
  echo "<tr>
    <td><span id='snum'>$i.</span>
    </td>
    <input class='form-control' type='hidden' id='hiddenlot_$i' name='hiddenlot[]' />
    <input class='form-control' type='hidden' id='hiddencustomer_$i' name='hiddencustomer[]' />
    <input class='form-control' type='hidden' id='hiddenprice_$i' name='hiddenprice[]' />
    <td>
      <input class='form-control' type='text' id='jenisbenang_$i' name='jenisbenang[]' readonly/>
    </td>
    <td>
      <input class='form-control' type='text' id='warna_$i' name='warna[]' readonly/>
    </td>
    <td>
      <input class='form-control' type='text' id='lot_$i' name='lot[]' required/>
    </td>
    <td>
      <input class='form-control sedang' type='text' id='netto_$i' name='netto[]' required/>
    </td>
    <td>
      <input class='form-control pendek' type='text' id='box_$i' name='box[]' />
    </td>
    <td>
      <input class='form-control pendek' type='text' id='cones_$i' name='cones[]' />
    </td>
    <td>
      <input class='form-control' type='text' id='keterangan_$i' name='keterangan[]' />
    </td>
    <td><a><span class='glyphicon glyphicon-plus addmore_$i'></span></a> 
    </td>
  </tr>
  <tr>
    <td colspan='10'>
      <div id='keatas_$i'>

      </div>
    </td>
  </tr>";
}

so ignore the code with input text-box , i want to append data to this :

<td colspan='10'>
  <div id='keatas_$i'>

  </div>
</td>
</tr>";

Any response would be appreciated!

Thanks.

Rajesh
  • 24,354
  • 5
  • 48
  • 79

1 Answers1

1

Your variable a is bind to its latest value, so it won't work. You need to make a copy of a:

var i = $('table tr').length;
var count = $('table tr').length;
var row = i;
var a = 0;

for (a = 0; a <= i; a++) {
  $(".addmore_" + a).on('click', function (_a) {
    return function() {
      var data = "<input class='form-control' type='text' id='packinglist_" + _a + "' name='packinglist[]'/>";
      $("#keatas_" + _a).append(data);
    } ;
  } (a));
};

Explanation:

I will use setTimeout instead of your custom callback because it is easier to see what happen. Let's start with a simple example:

for (var i = 0 ; i < 5 ; i++) {
    setTimeout (function () {
        console.log(i) ;
    }, 250) ;
}

If you don't know setTimeout, it will simply call the function you specified (first argument) after the amount of time specified by the second argument (in milliseconds, 250ms in this example).

The output you expect for the above code is:

0 1 2 3 4

But what you actually get is:

5 5 5 5 5

So, why is that?

When you create the lambda function in the loop, you do not bind the current value of i, so the i used in the lambda function is actually a reference to the loop variable i.

When the lambda functions get called, they will retrieve the current value of the i variable, which is 5 at the end of the loop, thus you get the above output.

How to deal with it?

What you want is force the lambda function to use the value that i had at the time you created it. One way to do it, is to create a function and immediately call it:

function (_i) {
    // whatever
} (i)

By calling the function, you "detach" your variable from its original reference i and give it to a new reference _i. But since you are creating a new reference _i at each loop, the value will be bind correctly.

What you need to do then is create and return another lambda function using your new variable _i by setTimeout:

function (_i) {
    return function () {
        console.log(_i) ;
    } ;
} (i)

The full code:

for (var i = 0 ; i < 5 ; i++) {
    setTimeout (function (_i) {
        return function () {
            console.log(_i) ;
        } ;
    } (i), 250) ;
}

Output:

0 1 2 3 4

Note that in the original code of this answer, I was using the name a to reference both the loop variable and the temporary copy, which was confusing.

Holt
  • 36,600
  • 7
  • 92
  • 139
  • WOW ! its workingg , thanks a lot dude but i still dont understand what the problem is , so i have to put 'a' into function and return it ? and what for 'a' at last row in your code ? but thanks a lot dude , you saved my life – Jeremy Hermawan Dec 17 '15 at 14:00
  • @JeremyHermawan See my updated answer, and feel free to comment if you don't understand everything. [This answer](http://stackoverflow.com/a/5226333/2666289) is closely related. This problem often arises in javascript when you try to call `setTimeout` in a loop or do AJAX call in loop (you may search for `javascript loop setTimeout/ajax` on google to find extra explanation). – Holt Dec 17 '15 at 14:16
  • i got it a little lol , but in my case i want to incrase the number of 'id='packinglist_" + _a + "'' and foreach i click "add more" the number of ID input text box will increase by 1 . i want trying your code for my 2nd problem but i dont know to do that , may you help me once again please ? – Jeremy Hermawan Dec 17 '15 at 14:30
  • @JeremyHermawan If you have a second problem (which is not in your original question), you should post a new question on SO. – Holt Dec 17 '15 at 14:33