我有一个表示项目的表单。表单包含一个提交按钮。如果单击提交按钮,则应对这些字段进行验证不引人注意的验证。
如果验证失败,则不会发生任何其他事情。
如果验证通过,则应将该项添加到Knockout.js observedArray集合中。
在这两种情况下,整个过程应保留在客户端,而无需提交给服务器。提交和服务器端验证将在流程的后期进行。
如何达到预期效果?
我正在使用ASP.Net MVC和Data Annotations。我不想在客户端手动复制验证逻辑。
我还应该提到我在同一页面上有几种形式。
这是我迄今为止所做的......
这是我的ASP.Net MVC布局文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - JC Guns Online</title>
@*---------- Stylesheets ----------*@
@Styles.Render("~/Content/Bootstrap/bootstrap-theme.css")
@Styles.Render("~/Content/MightyIT/bootstrap_customizations.css")
@Styles.Render("~/Content/site.css")
@Styles.Render("~/Content/MightyIT/custom_styles.css")
@Styles.Render("~/Content/MightyIT/callout.css")
@Styles.Render("~/Content/font-awesome-4.0.3/css/font-awesome.min.css")
@RenderSection("css", required: false)
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top">
<div class="container">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
@*<li>
@using (Html.BeginForm())
{
<input id="txtQuickSearch" type="text" class="form-control col-lg-8" placeholder="Search">
<img src="~/Content/img/search_32.png" />
}
</li>*@
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
<div class="container body-content">
<br />
@RenderBody()
<br /><br />
<nav class="navbar navbar-default navbar-fixed-bottom">
<div style="text-align:center">
<img src="~/Content/img/logo_small.png" class="img-responsive" />
<sub style="position:absolute; right:10px; bottom:10px;">© @DateTime.Now.Year </sub>
</div>
</nav>
</div>
@*---------- Javascripts ----------*@
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/bootstrap")
@Scripts.Render("~/Scripts/KnockOut/knockout-3.0.0.js")
@Scripts.Render("~/Scripts/JQuery/jquery.unobtrusive-ajax.js")
@Scripts.Render("~/Scripts/JQuery/jquery.validate.js")
@Scripts.Render("~/Scripts/JQuery/jquery.validate.unobtrusive.js")
@Scripts.Render("~/Scripts/JQuery/jquery.callout.unobtrusive.js")
@Scripts.Render("~/Scripts/MVCFoolProof/mvcfoolproof.unobtrusive.js")
@RenderSection("scripts",false)
</body>
</html>
以下是我目前正在处理的相关部分的代码(有几个类似的部分将放在同一页面上):
<form id="AddCrimeForm">
<div class="panel panel-success">
<div class="panel-heading">
<div class="form-horizontal">
<div class="row">
<div class="col-lg-11">Add a crime incident to the list</div>
<div class="col-lg-1">
<button type="submit" class="btn btn-success btn-xs" onclick="addCrime();"><i class="fa fa-plus"></i> Add</button>
</div>
</div>
</div>
</div>
<div class="panel-body">
<div class="form-horizontal">
<div class="row">
<div class="col-lg-6">
<input data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="Id" name="Id" type="hidden" value="">
<div class="form-group">
<label class="control-label col-md-4" for="CaseNumber">Case Number</label>
<div class="col-md-8">
<input class="form-control text-box single-line" data-val="true" data-val-required="The Case Number field is required." id="CaseNumber" name="CaseNumber" type="text" value="">
<span class="field-validation-valid" data-valmsg-for="CaseNumber" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-4" for="DateOfIncident">Date Of Incident</label>
<div class="col-md-8">
<input class="form-control text-box single-line valid" data-val="true" data-val-required="The Date of Incident field is required." id="DateOfIncident" name="DateOfIncident" type="date" value="">
<span class="field-validation-valid" data-valmsg-for="DateOfIncident" data-valmsg-replace="true"></span>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label class="control-label col-md-4" for="Description">Description</label>
<div class="col-md-8">
<textarea class="form-control text-box multi-line" data-val="true" data-val-required="The Description field is required." id="Description" name="Description"></textarea>
<span class="field-validation-valid" data-valmsg-for="Description" data-valmsg-replace="true"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<table class="table table-striped table-hover " id="CrimeList">
<thead>
<tr>
<th>Case Number</th>
<th>Date of Incident</th>
<th>Description</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td data-bind="text: $data.CaseNumber">Column content</td>
<td data-bind="text: $data.DateOfIncident">Column content</td>
<td data-bind="text: $data.Description" style="text-wrap: normal">Column content</td>
@*<td></td>
<td></td>
<td></td>*@
<td>...</td>
</tr>
</tbody>
</table>
以下是client_crime_kjs.js的代码,包含我所有的KnouckoutJS视图模型代码:
$(document).ready(
function ()
{
var Crime = function(CaseNumber, DateOfIncident, Description)
{
this.CaseNumber = CaseNumber;
this.DateOfIncident = DateOfIncident;
this.Description = Description;
}
var initialData = new Array();
var crimes = function (items)
{
var self = this;
//Data
self.items = ko.observableArray(items)
//operations
self.addCrime = function()
{
if ($("#AddCrimeForm").valid()) {
self.crime = new Crime($("#CaseNumber").val(), $("#DateOfIncident").val(), $("#Description").val());
//var JSONObj = { CaseNumber: $("#CaseNumber").val(), DateOfIncident: $("#DateOfIncident").val(), Description: $("#Description").val() };
self.items.push(this.crime);
}
//$("#CaseNumber").val() = "";
//$("#DateOfIncident").val() = "";
//$("#Description").val() = "";
}
}
ko.applyBindings(crimes(initialData), $("#CrimeList")[0])
}
);
基本上发生的是在这个阶段,当字段无效时,表单不提交(正确地如此),但是当它确认它确实提交时(违反我的要求),并且我的KO observablearray随后重置
答案 0 :(得分:2)
所以我得到了上述问题的答案。诀窍是设置按钮类型=“按钮”而不是“提交”。
所以,对于任何正在努力解决这个问题的人来说,这里有一个如何让它发挥作用的例子......
你的淘汰赛ViewModel:
$(document).ready(
function () {
var Crime = function (CaseNumber, DateOfIncident, Description) {
this.CaseNumber = CaseNumber;
this.DateOfIncident = DateOfIncident;
this.Description = Description;
}
var crimes = function (items) {
var self = this;
//Data
self.items = ko.observableArray(items)
//operations
self.addCrime = function () {
if ($("#AddCrimeForm").valid()) {
self.crime = new Crime($("#CaseNumber").val(), $("#DateOfIncident").val(), $("#Description").val());
//var JSONObj = { CaseNumber: $("#CaseNumber").val(), DateOfIncident: $("#DateOfIncident").val(), Description: $("#Description").val() };
self.items.push(this.crime);
$("#CaseNumber").val("");
$("#DateOfIncident").val("");
$("#Description").val("");
}
}
self.removeCrime = function (item) {
self.items().remove(item);
}
}
var initialData = new Array();
ko.applyBindings(crimes(initialData), $("#CrimeList")[0])
}
);
这是相应的HTML:
<form id="AddCrimeForm">
<div class="panel panel-success">
<div class="panel-heading">
<div class="form-horizontal">
<div class="row">
<div class="col-lg-11">Add a crime incident to the list</div>
<div class="col-lg-1">
<button type="button" class="btn btn-success btn-xs" onclick="addCrime();"><i class="fa fa-plus"></i> Add</button>
</div>
</div>
</div>
</div>
<div class="panel-body">
<div class="form-horizontal">
<div class="row">
<div class="col-lg-6">
<input data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="Id" name="Id" type="hidden" value="">
<div class="form-group">
<label class="control-label col-md-4" for="CaseNumber">Case Number</label>
<div class="col-md-8">
<input class="form-control text-box single-line" data-val="true" data-val-required="The Case Number field is required." id="CaseNumber" name="CaseNumber" type="text" value="">
<span class="field-validation-valid" data-valmsg-for="CaseNumber" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-4" for="DateOfIncident">Date Of Incident</label>
<div class="col-md-8">
<input class="form-control text-box single-line valid" data-val="true" data-val-required="The Date of Incident field is required." id="DateOfIncident" name="DateOfIncident" type="date" value="">
<span class="field-validation-valid" data-valmsg-for="DateOfIncident" data-valmsg-replace="true"></span>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label class="control-label col-md-4" for="Description">Description</label>
<div class="col-md-8">
<textarea class="form-control text-box multi-line" data-val="true" data-val-required="The Description field is required." id="Description" name="Description"></textarea>
<span class="field-validation-valid" data-valmsg-for="Description" data-valmsg-replace="true"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<table class="table table-striped table-hover " id="CrimeList">
<thead>
<tr>
<th>Case Number</th>
<th>Date of Incident</th>
<th>Description</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td data-bind="text: $data.CaseNumber">Column content</td>
<td data-bind="text: $data.DateOfIncident">Column content</td>
<td data-bind="text: $data.Description" style="text-wrap: normal">Column content</td>
@*<td></td>
<td></td>
<td></td>*@
<td>...</td>
</tr>
</tbody>
</table>
再一次 - 注意“添加”按钮的类型已设置为“按钮”而不是“提交”。
希望这有助于你所有人编写窥视的其余部分!
答案 1 :(得分:0)
我正在尝试做类似的事情。
我在开始时的想法和你的想法一样,但后来我做了一些修改,因为很难用数据注释进行复杂的验证。复杂意味着记录不会在数据库上重复,也不会在输入上重复自定义格式。
所以我去了FluentValidation,问题是流畅的验证并不总是在不显眼的验证中工作。所以我现在正在做的就是这个。
希望这对您有所帮助,如果您发现可能更好的东西,请告诉我们:
我的模型及其验证:
public class BUCashFlow
{
public int Id { get; set; }
[Display(Name = "Concepto")]
public string Text { get; set; }
[Display(Name = "Valor")]
public double Value { get; set; }
public CashFlowType CashFlowType { get; set; }
[Display(Name = "Cuenta")]
public int AccountId { get; set; }
public string User { get; set; }
public virtual Account Account { get; set; }
}
public class BuCashFlowVal : AbstractValidator<BUCashFlow>
{
public BuCashFlowVal()
{
RuleFor(p => p.Text)
.NotEmpty().WithMessage(ValHelper.Messages.Required);
RuleFor(p => p.Value)
.NotEmpty().WithMessage(ValHelper.Messages.Required);
RuleFor(p => p.AccountId)
.NotEmpty().WithMessage(ValHelper.Messages.Required);
}
}
我也在使用web api,所以这是我的web api控制器,我在那里验证我的新BUCashFlow模型
// POST api/BUCashFlows
[ResponseType(typeof(BUCashFlow))]
public IHttpActionResult PostBUCashFlow(BUCashFlow bucashflow)
{
ValidationResult ValRes = new BuCashFlowVal().Validate(bucashflow);
if (!ValRes.IsValid)
{
return BadRequest(ValRes.Errors[0].ErrorMessage);
}
bucashflow.User = User.Identity.GetUserId();
bucashflow.CashFlowType=CashFlowType.Purchase;
db.BuCashFlows.Add(bucashflow);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = bucashflow.Id }, bucashflow);
}
最后以js / ko显示我的错误我正在这样做:
self.addExpense = function(selector) {
$.ajax({
type: 'POST',
url: '@ViewBag.ApiBUExpenses',
data: $(selector).serialize()
}).done(function(o) {
self.expenses.push(new ExpenseVM(self, o.Id, o.Text, o.Value, o.AccountId));
}).fail(function (o) {
$(selector).find('.val').html( '<div class="alert alert-warning alert-dismissable">' +
'<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' +
'<strong>Warning!</strong> ' + o.responseJSON.Message +
'</div>');
});
};
和我在这个ajax Call中序列化的html表单:
<form id="new-expense-form" data-bind="submit: addExpense">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Agregar Nuevo Gasto</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label class="control-label">Concepto</label>
<input name="Text" type="text" class="form-control" />
</div>
<div class="form-group">
<label class="control-label">Valor</label>
<input name="Value" type="text" class="form-control" />
</div>
<div class="form-group">
<label class="control-label">Cuenta</label>
<i data-bind="visible: isLoadingAccounts" class="fa fa-refresh fa-spin pull-right"></i>
<select name="AccountId" class="form-control" data-bind="options: accounts, optionsText: 'name', optionsValue: 'Id', optionsCaption: 'Cuenta'"></select>
</div>
<div class="val"></div>
</div>
<div class="modal-footer">
<button class="btn btn-default-pnl btn-circle-m" title="Guardar Gasto">
<i class="fa fa-check"></i>
</button>
</div>
</form>
您对此方法有何看法?
感谢您分享这个库,现在如果这样可行,您只需要以这种方式更改ajax调用:
self.addExpense = function(selector) {
$(selector).validate()
if ($(selector).valid()) {
$.ajax({
type: 'POST',
url: '@ViewBag.ApiBUExpenses',
data: $(selector).serialize()
}).done(function(o) {
self.expenses.push(new ExpenseVM(self, o.Id, o.Text, o.Value, o.AccountId));
})
}
};
我看到了你的图书馆,我觉得它不会有用,如果没有,你总是可以复制你的验证并使用KnockoutValidation