JSFiddle - React, Tailwind, and code Playground
HTML
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min.js"></script>
<form method="post" id="formCreateNewItem" role="form">
<div id="item-prop-wrapper" class="dynamic-rows">
<h4>Items</h4>
<div class="form-group item-prop-body first-row">
<div class="col-sm-4">
<div class="form-group">
<!-- SKU -->
<label>SKU</label>
<input class="form-control" type="text" name="sku[]">
</div>
</div>
<div class="col-sm-4">
<div class="form-group">
<!-- Item price-->
<label>Price (Require)</label>
<div class="input-group"> <span class="input-group-addon">$</span>
<input class="form-control number-format item-price-input" type="text" name="itemPrice[]">
</div>
</div>
</div>
<div class="col-sm-4">
<div class="form-group">
<!-- Item Quantities -->
<label>Item Quantities</label>
<input class="form-control integer-format" type="text" name="itemQuant[]">
</div>
</div>
</div>
</div>
<button type="submit" class="btn btn-success" name="btnCreateNewItem">Create</button>
</form>
JavaScript
$(function () {
$('#formCreateNewItem').validate({
rules: {
itemName: {
required: true
},
'itemPrice[]': {
required: true
}
},
highlight: function (element) {
$(element).closest('.form-group').addClass('has-error');
},
unhighlight: function (element) {
$(element).closest('.form-group').removeClass('has-error');
},
errorElement: 'span',
errorClass: 'help-block',
errorPlacement: function (error, element) {
if (element.attr('name') == 'itemPrice[]') error.insertAfter(element.parent());
else error.insertAfter(element);
}
});
});
var itemSelector = 'input[name="sku[]"], input[name="itemQuant[]"]';
$('#item-prop-wrapper').on('keyup', itemSelector, function () {
$(this).closest('.item-prop-body').find('.item-price-input').rules('add', {
required: true
});
});
$('#item-prop-wrapper').on('keyup', '.item-price-input', function () {
cloneRow('.item-prop-body', this, '#item-prop-wrapper');
});
function cloneRow(rowWrapper, toClone, sectionWrapper) {
if ($(toClone).val() == '') return;
// Prevent creating new input box for every key press
else if ($(toClone).closest(rowWrapper).next().val() == '') return;
var currentRow = $(toClone).closest(rowWrapper);
var newRow = currentRow.clone();;
var newIDNum = newRow.attr('id') + 1;
var hasError = newRow.find('.has-error');
// Show remove icon for the current (to be cloned) row
currentRow.find('.remove-wrapper').css('display', 'inline-block');
if (hasError) hasError.removeClass('has-error');
newRow.attr('id', newIDNum);
newRow.find('input').val('');
// Append the new row to the end of sectionWrapper
$(sectionWrapper).append(newRow);
}