Reputation: 67283
If I create multiple elements like this...
@for (int i = 0; i < 10; i++)
{
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label asp-for="Railcars[i].RailcarNumber" class="control-label"></label>
<input asp-for="Railcars[i].RailcarNumber" class="form-control" />
<span asp-validation-for="Railcars[i].RailcarNumber" class="text-danger"></span>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="Railcars[i].Weight" class="control-label"></label>
<input asp-for="Railcars[i].Weight" class="form-control" />
<span asp-validation-for="Railcars[i].Weight" class="text-danger"></span>
</div>
</div>
</div>
}
Validation appears to work correctly for all rows.
However, if I create a single row like this...
<div class="railcars">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label asp-for="Railcars[0].RailcarNumber" class="control-label"></label>
<input asp-for="Railcars[0].RailcarNumber" class="form-control" />
<span asp-validation-for="Railcars[0].RailcarNumber" class="text-danger"></span>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="Railcars[0].Weight" class="control-label"></label>
<input asp-for="Railcars[0].Weight" class="form-control" />
<span asp-validation-for="Railcars[0].Weight" class="text-danger"></span>
</div>
</div>
</div>
</div>
And then clone rows using jQuery's clone()
, validation only appears to work for the first (non-cloned) row.
Note: I am taking care to update all the ID, name, and for attributes of the cloned elements, and updating the subscript number. I checked that it's correct and posts the correct information to the server. ModelState
even correctly detects validation problems with the cloned elements. It's just that client-side validation doesn't work on them.
Here is the HTML produced:
Uncloned Row (validation works):
<div class="row first-railcar">
<div class="col-md-4">
<div class="form-group railcar-number">
<label class="control-label" for="Railcars_0__Railcar">Railcar Number</label>
<input class="form-control" type="text" data-val="true" data-val-length="The field Railcar Number must be a string with a maximum length of 18." data-val-length-max="18" data-val-required="The Railcar Number field is required." id="Railcars_0__Railcar" maxlength="18" name="Railcars[0].Railcar" value="">
<span class="text-danger field-validation-valid" data-valmsg-for="Railcars[0].Railcar" data-valmsg-replace="true"></span>
</div>
</div>
<div class="col-md-4">
<div class="form-group railcar-volume">
<label class="control-label" for="Railcars_0__Volume">Volume (pounds)</label>
<input class="form-control" type="text" data-val="true" data-val-number="The field Volume (pounds) must be a number." data-val-required="The Volume (pounds) field is required." id="Railcars_0__Volume" name="Railcars[0].Volume" value="">
<span class="text-danger field-validation-valid" data-valmsg-for="Railcars[0].Volume" data-valmsg-replace="true"></span>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label"> </label><br>
<img class="add-railcar" src="/images/add.png" title="Add Additional Railcar" style="display: none;">
<img class="remove-railcar" src="/images/delete_2.png" title="Remove Railcar" style="display: none">
</div>
</div>
</div>
Cloned Row (validation doesn't work):
<div class="row">
<div class="col-md-4">
<div class="form-group railcar-number">
<label class="control-label" for="Railcars_1__Railcar">Railcar Number</label>
<input class="form-control" type="text" data-val="true" data-val-length="The field Railcar Number must be a string with a maximum length of 18." data-val-length-max="18" data-val-required="The Railcar Number field is required." id="Railcars_1__Railcar" maxlength="18" name="Railcars[1].Railcar" value="">
<span class="text-danger field-validation-valid" data-valmsg-for="Railcars[1].Railcar" data-valmsg-replace="true"></span>
</div>
</div>
<div class="col-md-4">
<div class="form-group railcar-volume">
<label class="control-label" for="Railcars_1__Volume">Volume (pounds)</label>
<input class="form-control" type="text" data-val="true" data-val-number="The field Volume (pounds) must be a number." data-val-required="The Volume (pounds) field is required." id="Railcars_1__Volume" name="Railcars[1].Volume" value="">
<span class="text-danger field-validation-valid" data-valmsg-for="Railcars[1].Volume" data-valmsg-replace="true"></span>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label"> </label><br>
<img class="add-railcar" src="/images/add.png" title="Add Additional Railcar">
<img class="remove-railcar" src="/images/delete_2.png" title="Remove Railcar" style="">
</div>
</div>
</div>
I also carefully compared the cloned HTML above to the HTML created by my first example (with the for
loop), and they are identical. Apparently, there is something different about it being added after the page has loaded.
Does anyone know how to clone elements this way and have validation work on all the cloned elements?
Update:
My use of jQuery's clone()
includes two true values ($row.clone(true, true)
). If I don't do this, the click handlers for my images don't work.
As recommended, I tried several variations of the following code after cloning the elements. But I couldn't get it to make any difference.
var form = document.getElementById('input-form');
$.validator.unobtrusive.parse(form);
Upvotes: 0
Views: 531
Reputation: 35554
You are on the right track with $.validator.unobtrusive.parse(form);
. However for jQuery Validation to work on copied/appended with ajax/cloned elements you need three things.
So here is a working example below.
<form>
<div class="container" id="ElementContainer">
<div id="ElementToClone">
<div class="row">
<div class="col col-md-4">
<div class="form-group">
<input class="form-control" type="text" name="elem[0]" id="elem_0" data-val="true" data-val-required="Required.">
</div>
</div>
</div>
</div>
</div>
<div class="pt-3">
<button type="button" class="btn btn-primary" onclick="Clone()">Clone</button>
<button type="submit" class="btn btn-primary ml-3">Submit</button>
</div>
</form>
<script>
function Clone() {
var $container = $('#ElementContainer');
var $elem = $('#ElementToClone');
var $form = $container.closest('form');
//duplicate x times
for (var i = 1; i <= 5; i++) {
var clonedHtml = $elem.html();
//create a unique name
clonedHtml = clonedHtml.replace('elem[0]', 'elem[' + i + ']');
//create an unique id (not required for validate to function)
clonedHtml = clonedHtml.replace('elem_0', 'elem_' + i);
//append the cloned element
$container.append(clonedHtml);
}
//remove validation from the inital input elements or it won't work
$form.removeData('validator').removeData('unobtrusiveValidation');
//bind the validation again
$.validator.unobtrusive.parse($form);
}
</script>
P.S. tested on MVC, not Core. But it should work the same since it is front-end anyways.
Upvotes: 2