Ric*_*cka 11 jquery unobtrusive-validation asp.net-mvc-4 knockout.js
使用MVC 4和KnockoutJS.我可以使用自定义敲除绑定绑定不显眼的验证吗?我目前正在使用模板重新绑定验证afterRender
.我很乐意让它自动添加绑定.像这样:
ko.bindingHandlers.egtZipRep = {
init: function (element, valueAccessor, allBindingsAccessor, context) {
$(element).inputmask("99999", { "placeholder": "?" });
egtUniqueNameBinding(element, ++ko.bindingHandlers['uniqueName'].currentIndex);
applyValidationRules(element); // Is it possible to do this here?
ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, context);
}
};
Run Code Online (Sandbox Code Playgroud)
我整天都在修整它.如果不是非常低效,我就做不到.
我目前这样做的方式如下.也许我应该对此感到高兴.但我猜之前有人试过这个.
self.ReferenceAfterRender = function (element) {
bindUnobtrusiveValidation(element);
}
// Bind validation on new content
function bindUnobtrusiveValidation(element) {
// Bind to fields - must be called everytime new field is created
$.validator.unobtrusive.parseDynamicContent(element);
}
$.validator.unobtrusive.parseDynamicContent = function (selector) {
// Use the normal unobstrusive.parse method
$.validator.unobtrusive.parse(selector);
// Get the relevant form
var form = $(selector).first().closest('form');
// Get the collections of unobstrusive validators, and jquery validators
// and compare the two
var unobtrusiveValidation = form.data('unobtrusiveValidation');
var validator = form.validate();
if (typeof (unobtrusiveValidation) != "undefined") {
$.each(unobtrusiveValidation.options.rules, function (elname, elrules) {
if (validator.settings.rules[elname] === undefined) {
var args = {};
$.extend(args, elrules);
args.messages = unobtrusiveValidation.options.messages[elname];
$('[name=' + elname + ']').rules("add", args);
} else {
$.each(elrules, function (rulename, data) {
if (validator.settings.rules[elname][rulename] === undefined) {
var args = {};
args[rulename] = data;
args.messages = unobtrusiveValidation.options.messages[elname][rulename];
$('[name=' + elname + ']').rules("add", args);
}
});
}
});
}
Run Code Online (Sandbox Code Playgroud)
有趣的问题!这是一种纯 KnockoutJS + VanillaJS 解决方案。可能会有一些皱纹、跨浏览器的东西(我正在看着你,IE!)和粗糙的边缘。如果您愿意,请在评论中告诉我或建议更新答案。
ViewModel 和验证规则:
验证规则应该接近 ViewModel 的属性,就像 .NET 中的属性一样。KnockoutJS 的文档建议为此目的使用扩展器。用法如下:
self.name = ko.observable("Bob-Martin");
self.name = self.name.extend({ regex: { pattern: "^[^0-9]*$", message: "No digits plz!" } })
self.name = self.name.extend({ regex: { pattern: "^[^-]*$", message: "No dashes plz!" } });
Run Code Online (Sandbox Code Playgroud)
扩展器的代码:
文档中的扩展器非常好而且简单。这是处理多个验证错误的替代方案(尽管它需要对具有相同消息的多个规则进行一些工作):
ko.extenders.regex = function(target, options) {
options = options || {};
var regexp = new RegExp(options.pattern || ".*");
var message = options.message || "regex is mad at you, bro!";
// Only create sub-observable if it hasn't been created yet
target.errors = target.errors || ko.observableArray();
function validate(newValue) {
var matched = regexp.test(newValue);
if (!matched && target.errors.indexOf(message) == -1) {
target.errors.push(message);
}
else if (matched && target.errors.indexOf(message) >= 0) {
// TODO: support multiple extender instances with same
// message yet different pattern.
target.errors.remove(message);
}
}
validate(target()); //initial validation
target.subscribe(validate); //validate whenever the value changes
return target; //return the original observable
};
Run Code Online (Sandbox Code Playgroud)
验证消息模板:
为了使视图干燥和验证不引人注目,我定义了一个用于验证错误的模板,如下所示:
self.name = ko.observable("Bob-Martin");
self.name = self.name.extend({ regex: { pattern: "^[^0-9]*$", message: "No digits plz!" } })
self.name = self.name.extend({ regex: { pattern: "^[^-]*$", message: "No dashes plz!" } });
Run Code Online (Sandbox Code Playgroud)
视图:
实际的视图可以非常简单:
ko.extenders.regex = function(target, options) {
options = options || {};
var regexp = new RegExp(options.pattern || ".*");
var message = options.message || "regex is mad at you, bro!";
// Only create sub-observable if it hasn't been created yet
target.errors = target.errors || ko.observableArray();
function validate(newValue) {
var matched = regexp.test(newValue);
if (!matched && target.errors.indexOf(message) == -1) {
target.errors.push(message);
}
else if (matched && target.errors.indexOf(message) >= 0) {
// TODO: support multiple extender instances with same
// message yet different pattern.
target.errors.remove(message);
}
}
validate(target()); //initial validation
target.subscribe(validate); //validate whenever the value changes
return target; //return the original observable
};
Run Code Online (Sandbox Code Playgroud)
不引人注目且 DRY,因为这里没有带有验证消息的标记。(如果您想要特殊的验证标记,您可以使用value
绑定并为 . 创建单独的标记name.errors
。)
自定义绑定:
自定义绑定只会按顺序执行:
name
可观察数据作为数据。value
和valueUpdate
绑定。这是绑定(可能需要一些重构,并且喜欢 jQuery/javascript):
ko.bindingHandlers.valueWithValidation = {
init: function (element, valueAccessor, allBindingsAccessor) {
// Interception! Add validation markup to the DOM and
// apply the template binding to it. Some of this code
// can be more elegant, especially if you use jQuery or
// a similar library.
var validationElement = document.createElement("span");
element.parentNode.insertBefore(validationElement, element.nextSibling);
ko.applyBindingsToNode(validationElement, { template: { name: 'validation', data: valueAccessor().errors } });
// The rest of this binding is handled by the default
// value binding. Pass it on!
ko.applyBindingsToNode(element, { value: valueAccessor(), valueUpdate: 'afterkeydown' });
}
};
Run Code Online (Sandbox Code Playgroud)
演示:
要查看所有这些的实际效果,请查看这个 jsfiddle。