敲除验证 valueUpdate 取决于属性错误
Knockout validation valueUpdate depending on attribute error
是否可以将属性值更新从 "onblur" 更改为 "keyup",具体取决于属性是否附加了错误?
我想模仿 jQuery Validation 中的验证方式,首先对 blur 进行验证,然后对 keyup 进行验证。
这可能吗?
编辑:
让我澄清一下并举个例子。我不介意在 "keyup" 上绑定到模型,我介意的是在用户完成输入之前就显示一条错误消息。相反,如果我以验证电子邮件地址为例。如果用户输入无效的电子邮件,我希望错误显示模糊,如果用户再次将焦点放在该字段上以更正错误,我希望错误在更正后消失。另一方面,如果用户一开始输入的是有效的电子邮件,后来出现错误,则错误应该立即显示。
第二次编辑:
所以我考虑了一下,我认为验证不应该干扰模型绑定,而是应该对错误消息的显示进行更改。如前所述,我希望错误发生后立即出现,但只有在相关字段发生更改事件后才会出现。
我制作了这个 fiddle 几乎 有效,但它应该准确显示我正在努力完成的事情。
http://jsfiddle.net/mntm1bne/3/
<div data-bind="validationOptions: {messageTemplate: 'myCustomTemplate'}">
<input data-bind="value: firstName, valueUpdate: 'keyup', event: {change: firstName.enableD}" />
<br />
<input data-bind="value: lastName" />
<div data-bind="if: firstName.isD">
Firstname is dirty!
</div>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
<div data-bind="text: ko.toJSON($data)"></div>
</div>
<script type="text/html" id="myCustomTemplate">
<span data-bind="visible: field.isD && !field.isValid(), attr: { title: field.error }">X</span>
</script>
ko.extenders.trackChange = function(target, track) {
if (track) {
target.isD = ko.observable(false);
target.enableD = function() {
console.log("enable!");
target.isD(true);
}
}
return target;
};
var ViewModel = function () {
var self = this;
self.firstName = ko.observable().extend({ trackChange: true, required: { message: "firstName" }, number: true,
min: 0,
max: 100
});
self.lastName = ko.observable().extend({ required: { message: "lastName" }});
}
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
具体来说,错误在于页面加载时显示的第一条验证消息。
为了正确地做到这一点,您需要重写 valueUpdate
绑定,以便它接受一个 observable,并且您的 observable 将基于该值是否有错误。
这听起来很难,所以我选择了一些更骇人听闻的东西。我用 event
绑定替换了 valueUpdate
。它在 keydown 时触发,如果验证变量无效,则从输入更新它的值(使用 event.target
)。该值将始终在模糊时更新,因此我不必处理它。
var viewModel = {
num1: ko.observable(50).extend({
number: true,
min: 0,
max: 100
}),
maybeEvaluate: function(data, event) {
setTimeout(function() {
if (!viewModel.num1.isValid()) {
viewModel.num1(event.target.value);
}
}, 0);
return true;
}
};
ko.applyBindings(viewModel);
.validationMessage {
color: Red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
0-100:
<input data-bind="value: num1, event: {keydown: maybeEvaluate}" />
<span class="validationMessage" data-bind="validationMessage: num1"></span>
<br />
<input />
这是另一种方法,基于 protected observables。 protected observables 的最初设计是让您可以选择提交或重置更改。我有一个事件强制提交模糊,如果当前值无效,则在接收到新值时将受保护修改为 auto-commit。 (我不需要重置例程,所以我把它去掉了,所以请注意 protectedObservable
定义是自定义的。)
Update 根据您的评论(以及我没有包含所需库的事实),我更新了第二个示例,以便如果该字段有曾经有过错误,变成了continuously-validating.
ko.protectedObservable = function(initialValue) {
//private variables
var _actualValue = ko.observable(initialValue),
_tempValue = initialValue,
hasHadError = false;
//computed observable that we will return
var result = ko.computed({
//always return the actual value
read: function() {
return _actualValue();
},
//stored in a temporary spot until commit
write: function(newValue) {
_tempValue = newValue;
if (!result.isValid()) {
hasHadError = true;
}
if (hasHadError) {
result.commit();
}
}
}).extend({
notify: "always"
});
//if different, commit temp value
result.commit = function() {
if (_tempValue !== _actualValue()) {
_actualValue(_tempValue);
}
};
return result;
};
var viewModel = {
num1: ko.protectedObservable(50).extend({
number: true,
min: 0,
max: 100
})
};
ko.applyBindings(viewModel);
.validationMessage {
color: Red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
0-100:
<input data-bind="value: num1, valueUpdate: 'input', event: {blur: num1.commit}" />
<span class="validationMessage" data-bind="validationMessage: num1"></span>
<br />
<input />
是否可以将属性值更新从 "onblur" 更改为 "keyup",具体取决于属性是否附加了错误?
我想模仿 jQuery Validation 中的验证方式,首先对 blur 进行验证,然后对 keyup 进行验证。
这可能吗?
编辑: 让我澄清一下并举个例子。我不介意在 "keyup" 上绑定到模型,我介意的是在用户完成输入之前就显示一条错误消息。相反,如果我以验证电子邮件地址为例。如果用户输入无效的电子邮件,我希望错误显示模糊,如果用户再次将焦点放在该字段上以更正错误,我希望错误在更正后消失。另一方面,如果用户一开始输入的是有效的电子邮件,后来出现错误,则错误应该立即显示。
第二次编辑: 所以我考虑了一下,我认为验证不应该干扰模型绑定,而是应该对错误消息的显示进行更改。如前所述,我希望错误发生后立即出现,但只有在相关字段发生更改事件后才会出现。
我制作了这个 fiddle 几乎 有效,但它应该准确显示我正在努力完成的事情。
http://jsfiddle.net/mntm1bne/3/
<div data-bind="validationOptions: {messageTemplate: 'myCustomTemplate'}">
<input data-bind="value: firstName, valueUpdate: 'keyup', event: {change: firstName.enableD}" />
<br />
<input data-bind="value: lastName" />
<div data-bind="if: firstName.isD">
Firstname is dirty!
</div>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
<div data-bind="text: ko.toJSON($data)"></div>
</div>
<script type="text/html" id="myCustomTemplate">
<span data-bind="visible: field.isD && !field.isValid(), attr: { title: field.error }">X</span>
</script>
ko.extenders.trackChange = function(target, track) {
if (track) {
target.isD = ko.observable(false);
target.enableD = function() {
console.log("enable!");
target.isD(true);
}
}
return target;
};
var ViewModel = function () {
var self = this;
self.firstName = ko.observable().extend({ trackChange: true, required: { message: "firstName" }, number: true,
min: 0,
max: 100
});
self.lastName = ko.observable().extend({ required: { message: "lastName" }});
}
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
具体来说,错误在于页面加载时显示的第一条验证消息。
为了正确地做到这一点,您需要重写 valueUpdate
绑定,以便它接受一个 observable,并且您的 observable 将基于该值是否有错误。
这听起来很难,所以我选择了一些更骇人听闻的东西。我用 event
绑定替换了 valueUpdate
。它在 keydown 时触发,如果验证变量无效,则从输入更新它的值(使用 event.target
)。该值将始终在模糊时更新,因此我不必处理它。
var viewModel = {
num1: ko.observable(50).extend({
number: true,
min: 0,
max: 100
}),
maybeEvaluate: function(data, event) {
setTimeout(function() {
if (!viewModel.num1.isValid()) {
viewModel.num1(event.target.value);
}
}, 0);
return true;
}
};
ko.applyBindings(viewModel);
.validationMessage {
color: Red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
0-100:
<input data-bind="value: num1, event: {keydown: maybeEvaluate}" />
<span class="validationMessage" data-bind="validationMessage: num1"></span>
<br />
<input />
这是另一种方法,基于 protected observables。 protected observables 的最初设计是让您可以选择提交或重置更改。我有一个事件强制提交模糊,如果当前值无效,则在接收到新值时将受保护修改为 auto-commit。 (我不需要重置例程,所以我把它去掉了,所以请注意 protectedObservable
定义是自定义的。)
Update 根据您的评论(以及我没有包含所需库的事实),我更新了第二个示例,以便如果该字段有曾经有过错误,变成了continuously-validating.
ko.protectedObservable = function(initialValue) {
//private variables
var _actualValue = ko.observable(initialValue),
_tempValue = initialValue,
hasHadError = false;
//computed observable that we will return
var result = ko.computed({
//always return the actual value
read: function() {
return _actualValue();
},
//stored in a temporary spot until commit
write: function(newValue) {
_tempValue = newValue;
if (!result.isValid()) {
hasHadError = true;
}
if (hasHadError) {
result.commit();
}
}
}).extend({
notify: "always"
});
//if different, commit temp value
result.commit = function() {
if (_tempValue !== _actualValue()) {
_actualValue(_tempValue);
}
};
return result;
};
var viewModel = {
num1: ko.protectedObservable(50).extend({
number: true,
min: 0,
max: 100
})
};
ko.applyBindings(viewModel);
.validationMessage {
color: Red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
0-100:
<input data-bind="value: num1, valueUpdate: 'input', event: {blur: num1.commit}" />
<span class="validationMessage" data-bind="validationMessage: num1"></span>
<br />
<input />