动态添加的元素验证错误



我已经在我的模型的属性上放了一些只接受数字的正则表达式。

public class MaterialsViewModel
{
[Display(Name = "Material")]
public string MaterialName { get; set; }
[Range(typeof(int), "0", "999")]
[RegularExpression(@"^d+$", ErrorMessage = "Please enter proper value")]
public int? Quantity { get; set; }
[RegularExpression(@"^d+$", ErrorMessage = "Please enter proper value")]
public double? Cost { get; set; }
public IEnumerable<SelectListItem> CategoryList { get; set; }
public int SelectedCategory { get; set; }
public string SelectedCategoryName { get; set; }
}

我有我的视图,可以在其中动态添加控件

Dynamically add ScopeOfWork and Materials<br />
<div id="scopes">
<h3>Scopes</h3>
<a href="javascript:void(0)" id="addScope">Add Scope of Work</a>
@for (int i = 0; i < Model.ScopeOfWork.Count; i++)
{
<div class="scope">
<div class="form-group">
@Html.LabelFor(m => m.ScopeOfWork[i].ScopeOfWorkName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.ScopeOfWork[i].ScopeOfWorkName, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.ScopeOfWork[i].ScopeOfWorkName)
</div>
</div>
<input type="hidden" class="scopeindex" name="ScopeOfWork.Index" value="@i" />
<div class="indent materials">
<h4>Material</h4>
<a href="javascript:void(0)" class="addmaterial">Add Material</a>
@for (int j = 0; j < Model.ScopeOfWork[i].Materials.Count; j++)
{
<div class="material">
<div class="form-group">
@Html.LabelFor(m => m.ScopeOfWork[i].Materials[j].MaterialName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-2">
@Html.TextBoxFor(m => m.ScopeOfWork[i].Materials[j].MaterialName, new { @class = "form-control" })
</div>
<div class="col-md-10 col-md-offset-2">
@Html.ValidationMessageFor(m => m.ScopeOfWork[i].Materials[j].MaterialName)
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.ScopeOfWork[i].Materials[j].Quantity, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-1">
@Html.TextBoxFor(m => m.ScopeOfWork[i].Materials[j].Quantity, new { @class = "form-control" })
</div>
<div class="col-md-10 col-md-offset-2">
@Html.ValidationMessageFor(m => m.ScopeOfWork[i].Materials[j].Quantity)
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.ScopeOfWork[i].Materials[j].Cost, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-1">
@Html.TextBoxFor(m => m.ScopeOfWork[i].Materials[j].Cost, new { @class = "form-control" })
</div>
<div class="col-md-10 col-md-offset-2">
@Html.ValidationMessageFor(m => m.ScopeOfWork[i].Materials[j].Cost)
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2">Category</label>
<div class="col-xs-2">
@Html.DropDownListFor(m => m.ScopeOfWork[i].Materials[j].SelectedCategory, Model.ScopeOfWork[i].Materials[j].CategoryList, "Please select", htmlAttributes: new { @class = "form-control" })
</div>
</div>
<input type="hidden" class="materialindex" name="ScopeOfWork[@i].Materials.Index" value="@j" />
</div>
}
</div>
</div>
}
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-success" />
</div>
</div>
</div>
}

<div id="newScope" style="display:none">
<div class="scope">
<div class="form-group">
<label for="_#__ScopeOfWorkName" class="control-label col-md-2">Scope Of Work</label>
<div class="col-md-10">
<input class="form-control" type="text" id="_#__ScopeOfWorkName" name="ScopeOfWork[#].ScopeOfWorkName" value="">
<span class="field-validation-valid text-danger" data-valmsg-for="ScopeOfWork[#].ScopeOfWorkName" data-valmsg-replace="true"></span>
</div>
</div>
<input type="hidden" class="scopeindex" name="ScopeOfWork.Index" value="#" />
<div class="materials">
<h4>Material</h4>
<a href="javascript:void(0)" class="addmaterial">Add Material</a>
</div>
<hr />
</div>
</div>
<div id="newMaterial" style="display:none">
<div class="form-group">
<label for="_#__Materials_%__MaterialName" class="control-label col-md-2">Material</label>
<div class="col-md-2">
<input class="form-control" type="text" id="_#__Materials_%__MaterialName" name="ScopeOfWork[#].Materials[%].MaterialName" value="">
<span class="field-validation-valid text-danger" data-valmsg-for="ScopeOfWork[#].Materials[%].MaterialName" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label for="_#__Materials_%__Quantity" class="control-label col-md-2">Quantity</label>
<div class="col-md-1">
<input class="form-control" type="text" id="_#__Materials_%__Quantity" name="ScopeOfWork[#].Materials[%].Quantity" value="">
<span class="field-validation-valid text-danger" data-valmsg-for="ScopeOfWork[#].Materials[%].Quantity" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label for="_#__Materials_%__Cost" class="control-label col-md-2">Cost</label>
<div class="col-md-1">
<input class="form-control" type="text" id="_#__Materials_%__Cost" name="ScopeOfWork[#].Materials[%].Cost" value="">
<span class="field-validation-valid text-danger" data-valmsg-for="ScopeOfWork[#].Materials[%].Cost" data-valmsg-replace="true"></span>
</div>
</div>
@*Drop down*@
<div class="form-group">
<label for="_#__Materials_%__SelectedCategory" class="control-label col-md-2">Category</label>
<div class="col-xs-2">
<select class="form-control category" id="_#__Materials_%__SelectedCategory" name="ScopeOfWork[#].Materials[%].SelectedCategory">
<option value="">--Select--</option>
</select>
</div>
</div>
<input type="hidden" class="materialindex" name="ScopeOfWork[#].Materials.Index" value="%" />
</div>
<script>
var form = $('form');
var scope = $('#newScope');
var material = $('#newMaterial');
var categories = @Html.Raw(Json.Encode(Model.CategoryList));
form.on('click', '.addmaterial', function () {
var clone = material.clone();
var scopeIndex = $(this).closest('.scope').find('.scopeindex').val();
clone.html($(clone).html().replace(/#/g, scopeIndex));
var materialIndex = new Date().getTime();
clone.html($(clone).html().replace(/%/g, materialIndex));
// drop down list
var select = clone.find('.category');
$.each(categories, function(index, item) {
select.append($('<option></option>').val(item.Value).text(item.Text));
});
$(this).closest('.materials').append(clone.html());
form.data('validator', null);
$.validator.unobtrusive.parse(form);
});
$('#addScope').click(function () {
var clone = scope.clone();
var scopeIndex = new Date().getTime();
clone.html($(clone).html().replace(/#/g, scopeIndex));
$('#scopes').append(clone.html());
form.data('validator', null);
$.validator.unobtrusive.parse(form);
});
</script>

控制器:

[HttpPost]
public ActionResult _CreateProject(ProjectViewModel project)
{
tblProject projectModel = new tblProject();
tblScopeOfWork scopeModel = new tblScopeOfWork();
tblMaterial materialModel = new tblMaterial();
if (ModelState.IsValid)
{
projectModel.ProjectName = project.ProjectName;
projectModel.ProjectLocation = project.ProjectLocation;
projectModel.ProjectDescription = project.ProjectDescription;
projectModel.WorkArea = project.WorkArea;
projectModel.ModeOfPayment = project.ModeOfPayment;
projectModel.Duration = project.Duration;
projectModel.StartDate = project.StartDate;
projectModel.EndDate = project.EndDate;
projectModel.ProfitSupervision = project.ProfitSupervision;
projectModel.ProjectStatus = project.ProjectStatus;
projectModel.ForemanId = project.ForemanId;
projectModel.ClientId = project.ClientId;
db.tblProjects.Add(projectModel);
db.SaveChanges();
//Get the recently created ProjectId
var recentProjectId = db.tblProjects.OrderByDescending(x => x.ProjectId).FirstOrDefault().ProjectId;
//Get all values from List of ScopeOfWork
//Add each ScopeOfWork to the database
for (int scopeIndex = 0; scopeIndex < project.ScopeOfWork.Count; scopeIndex++)
{
scopeModel = new tblScopeOfWork();
scopeModel.ScopeOfWork = project.ScopeOfWork[scopeIndex].ScopeOfWorkName;
scopeModel.ProjectId = recentProjectId;
db.tblScopeOfWorks.Add(scopeModel);
db.SaveChanges();
//Get the recently created ScopeOfWorkId
var recentScopeOfWorkId = db.tblScopeOfWorks.OrderByDescending(x => x.ScopeOfWorkId).FirstOrDefault().ScopeOfWorkId;
//Get all materials from its corresponding ScopeOfWork and save to database
for (int materialIndex = 0; materialIndex < project.ScopeOfWork[scopeIndex].Materials.Count; materialIndex++)
{
materialModel = new tblMaterial();
materialModel.Description = project.ScopeOfWork[scopeIndex].Materials[materialIndex].MaterialName;
materialModel.Quantity = project.ScopeOfWork[scopeIndex].Materials[materialIndex].Quantity;
materialModel.Cost = project.ScopeOfWork[scopeIndex].Materials[materialIndex].Cost;
materialModel.ScopeOfWorkId = recentScopeOfWorkId;
materialModel.CategoryId = project.ScopeOfWork[scopeIndex].Materials[materialIndex].SelectedCategory;
db.tblMaterials.Add(materialModel);
}
}
db.SaveChanges();
}
project.ScopeOfWork = new List<ScopeOfWorkViewModel>
{
new ScopeOfWorkViewModel()
{
Materials = new List<MaterialsViewModel>
{
new MaterialsViewModel()
{
CategoryList = new SelectList(db.tblCategories, "CategoryId", "CategoryName")
}
}
}
};
return View(project);
}
}

问题是我试图在数量和成本的文本框上放置一些字符串('ss'),看看验证是否有效,这看起来The value 'ss' is not valid for QuantityThe value 'ss is not valid for Cost.,但它应该是Please enter proper value的。而且每当进行验证时,Add Material链接都无法添加另一个newMaterial

我已经尝试并检查了这些答案以及DotNetFiddle,但它仍然有一些错误。

你不需要你的正则表达式(它是一个int所以它只能接受一个数字)。cost属性也是如此(但是如果你不允许分数,为什么要把它变成十进制?

将首先执行类型的验证,并且由于其无效,因此不执行进一步的验证。

将属性更改为[Required]

[Range(typeof(int), "0", "999")]
[Required(ErrorMessage = "Please enter proper value")]
public int? Quantity { get; set; }

另请参阅此问题/答案,以更改type无效值的默认错误消息。

作为旁注,动态添加的项不会提供客户端验证,因为您尚未添加必要的data-val-*属性。需要检查为for循环中的元素生成的 html,并准确复制 html,但替换集合索引器除外。

POST 方法也存在问题,因为您将ScopeOfWork属性设置为新集合,并在返回视图之前清除用户输入的所有数据。POST 方法的基本结构应该是

[HttpPost]
public ActionResult _CreateProject(ProjectViewModel project)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(project);
return View(project);
}
// code to initialize your data models, save and redirect
}
private void ConfigureViewModel(ProjectViewModel model)
{
var categories = db.tblCategories;
model.CategoryList = new SelectList(categories , "CategoryId", "CategoryName");
foreach (var scope in model.ScopeOfWork)
{
foreach (var material in scope.Materials)
{
material.CategoryList = new SelectList(categories , "CategoryId", "CategoryName");
}
}
}

注意ConfigureviewModel()方法也是从 GET 方法调用的,以填充选择列表

最新更新