Reputation: 4434
I am using jquery to duplicate several html fields based on user's selection. However, I met an interesting problem. In general, I am asking users to select how many applications they want:
if there is only one application: a. One need to choose application method (for simplicity, only 'aerial' is available); b. after selecting 'aerial', it will ask you for the further information, chemically application method (CAM).
if they choose two applications, jquery code will clone and rename the necessary questions for you.
My problem is when I choose there are two applications, the sub-question 'CAM' will not show up. After some trouble shoot, I found the problem could be in this javascript :$('.app_method:last').find('select').change(function()
. The statement, automatically increase my loop index by one (Can anyone tell me why this will happen?), which mismatch the code.
Here is a DEMO for my code:
Below is my html code:
<div class="articles">
<table align="center">
<tr><th><label for="id_NOA">Number of applications:</label></th><td><select name="NOA" id="id_NOA">
<option value="1" selected="selected">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select></td></tr>
<tr><th><label for="id_Ap_m">Application method 1</label></th><td><select name="Ap_m" id="id_Ap_m">
<option value="" selected="selected">Select an application method</option>
<option value="1">Aerial</option>
</select></td></tr>
<tr><th><label for="id_CAM_1">Chemical application Method (CAM) 1</label></th><td><select name="CAM_1" id="id_CAM_1">
<option value="2">2-Interception based on crop canopy</option>
<option value="9">9-Linear foliar based on crop canop</option>
</select></td></tr>
</table>
</div>
jquery code:
$(document).ready(function() {
//this part of code controls inputs when there is only one application
$('#id_CAM_1').attr('id', 'id_1').closest('tr').addClass('method_options').hide();
$('#id_Ap_m').change(function() {
$('tr.method_options').hide();
if ($(this).val() == "1") {
$('#id_' + $(this).val()).closest('tr').show();
}
});
i = 1;
$('.articles').find('table').addClass('table');
$('#id_Ap_m').closest('tr').addClass('app_method');
$('#id_NOA').change(function() {
var total = $(this).val();
//remove all
$('.app_method').each(function(index) {
if (index != 0) $(this).remove()
});
//create new ones
for (var i = 2; i <= total; i++) {
alert('a=' + i);
$('.app_method:first').clone().appendTo('.table').find('label').text('Application method ' + i);
$('.app_method:last').find('select').attr('name', 'Ap_m' + i).attr('id', 'id_Ap_m' + i);
alert('b=' + i);
$('<tr class="method_options_1' + i + '" style="display: none;"><th><label for="id_CAM_1">Chemical application Method (CAM)' + i + '</label></th><td><select name="CAM_1_' + i + '" id="id_1_' + i + '"><option value="2">2-Interception based on crop canopy</option><option value="9">9-Linear foliar based on crop canop</option></select></td></tr>').appendTo('.table');
alert('c=' + i);
//The following statement increase the loop index by one, which causes me problems. Can
//anyone let me know why this could happen?
$('.app_method:last').find('select').change(function() {
alert('d=' + i)
$('.method_options_1').hide();
alert('e=' + i);
if ($(this).val() == "1") {
alert('e=' + i);
$('.method_options_1' + i).show();
}
})
}
})
})
Upvotes: 0
Views: 298
Reputation: 10114
I think this can be done much more simply: (fiddle: http://jsfiddle.net/QaHWz/)
<!DOCTYPE html><html><head></head><body>
<table align="center"><tbody>
<tr><th></th><td><a href="#" id="add_application">Add Application</a></td></tr>
</tbody></table>
<table id="template" style="display:none"><tbody>
<tr>
<th><label for="id_Ap_m_{n}">Application method {n}</label></th>
<td>
<select class="Ap_m" name="Ap_m_{n}" id="id_Ap_m_{n}" data-application="{n}">
<option value="" selected="selected">Select an application method</option>
<option value="1">Aerial</option>
</select>
</td></tr>
<tr style="display:none" class="app_{n} method_1"><th><label for="id_CAM_{n}">Chemical Application Method (CAM) {n}</label></th><td><select name="CAM_{n}" id="id_CAM_{n}">
<option value="2">2-Interception based on crop canopy</option>
<option value="9">9-Linear foliar based on crop canopy</option>
</select></td></tr>
</tbody></table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
jQuery(function($) {
var applications = 0;
$('#add_application').click(function() {
applications++;
var last_row = $(this).closest('tr');
last_row.before(jQuery('#template tbody').html().replace(/{n}/g, applications));
});
$(document).delegate('.Ap_m', 'change', function() {
var app = $(this).data('application');
$('.app_'+app).hide();
$('.app_'+app+'.method_'+this.value).show();
});
});
</script>
</body></html>
EDIT: The problem you are having with .change()
is that you are using the i
variable , which gets incremented before the function is run. You need to get the value of i
into the function another way. Here is one possible way you can do it:
$('.app_method:last').find('select').bind('change', { row: i }, function(event) {
var i = event.data.row;
alert('d=' + i)
// ...
});
The { row: i }
bit causes jQuery to attach this data to the event object which is passed to the function. Then I create var i
inside the scope of the function, which will not be affected by the i
outside, and assign this value to it.
Upvotes: 2