What I am trying to achieve:
My form consists of four fields of
#item
,#unit
,#price
, and#total
.A user can input multiple lines of
#item
and#unit
. For this, if the user clicks on "Add new line', there will appear a new line to receive user input for item and unit (quantity). If the user clicks on "-" on an already existing line, the line will be removed.Which item is selected is identified on real-time using javascript
change()
.The price of the selected item is dynamically retrieved using ajax and the price data is appended into the
#price
element and#total
element is also filled up by calculating#unit x #price
.
To achieve this, here's what I did.
First, my HTML form as below.
<form id="form">
<input type="submit" name="create" value="Create" />
<!-- dynamically add more lines -->
<div class="form-group table-row hide" id="template">
<!-- remove button-->
<div class="table-cell" style="width: 45px;">
<a class="btn btn-default removeButton">
<span class="glyphicon glyphicon-minus">
</span>
</a>
</div>
<!-- user input: item -->
<div class="table-cell">
<select id="item" class="form-control">
<option value=""></option>
<option value="item-1">Item 1</option>
<option value="item-2">Item 2</option>
<option value="item-3">Item 3</option>
</select>
</div>
<!-- user input: quantity -->
<div class="table-cell">
<input id="unit" min="1" step="1" value="1" type="number" class="form-control" />
</div>
<!-- price is dynamically filled up using ajax -->
<div class="table-cell">
<input id="price" type="text" class="form-control" />
</div>
<!-- total is dynamically calculated -->
<div class="table-cell">
<input id="total" type="text" class="form-control" />
</div>
</div>
<button type="button" class="btn btn-default addButton">Add new line</button>
</form>
And javascript code to implement dynamic add/remove of input forms.
<script>
jQuery(document).ready(function($) {
var idx = new Number( 0 );
$('#form')
// Add button click handler
.on('click', '.addButton', function() {
var $template = $('#template'),
$clone = $template
.clone()
.removeClass('hide')
.removeAttr('id')
.insertBefore($template);
// assign name attributes with proper array name and index
$clone.find('#item').attr('name', 'lines[' + idx + '][item]').attr('required', 'required').val('');
$clone.find('#unit').attr('name', 'lines[' + idx + '][unit]').attr('required', 'required').val('');
$clone.find('#price').attr('name', 'lines[' + idx + '][price]').attr('required', 'required').val('');
$clone.find('#total').attr('name', 'lines[' + idx + '][total]').val('');
idx = idx + 1;
})
// Remove button click handler
.on('click', '.removeButton', function() {
if (confirm("<?php _e( 'Are you sure you wish to remove this line? This cannot be undone.', 'doumi' ); ?>")) {
var $row = $(this).parents('.form-group');
// Remove element containing the option
$row.remove();
idx = idx - 1;
}
});
});
</script>
Lastly, jQuery to call ajax.
<script>
/* Get Item Price */
jQuery('#item').change(function(){
var $item_id=$('#item').val();
var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
// call ajax
jQuery("#price").empty();
jQuery.ajax({
url: ajaxurl,
/* ******************************************************************** */
/* ajax_get_item_price is a function that returns the price of the item */
/* ******************************************************************** */
data:' action=ajax_get_item_price&item_id='+$item_id,
type:'GET',
success:function(results) {
jQuery("#price").append(results);
}
});
});
</script>
I have no problem dynamically adding and removing lines for the input form.
The problem is that form elements in each line is given a name as an array like below;
<select id="item" name="lines[0][item]"></select>
<input id="unit" name="lines[0][unit]" />
<input id="price" name="lines[0][price]" />
<input id="total" name="lines[0][total]" />
<select id="item" name="lines[1][item]"></select>
<input id="unit" name="lines[1][unit]" />
<input id="price" name="lines[1][price]" />
<input id="total" name="lines[1][total]" />
<select id="item" name="lines[2][item]"></select>
<input id="unit" name="lines[2][unit]" />
<input id="price" name="lines[2][price]" />
<input id="total" name="lines[2][total]" />
...
...
...
<select id="item" name="lines[n][item]"></select>
<input id="unit" name="lines[n][unit]" />
<input id="price" name="lines[n][price]" />
<input id="total" name="lines[n][total]" />
I guess that since there are multiple #item
s with varying names, jQuery does not know which #item
it needs to pay attention to. However, I have no idea, either, as to how to properly call ajax with the concerned #item.
Any advice is highly appreciated.