使用knockout.validation时,isValid属性会错误地报告其状态,但只有当它在ko.foreach“内部”时才会报告。
使用下面的代码段,如果您在同一文本框中运行并输入以下值(q,z,10),您将获得以下输出:
如您所见,验证规则适用于数字,q不应报告为真,10不应报告错误。
执行顺序似乎搞砸了,因为InvoiceAmount.subcribe是在InvoiceAmount.isValid.subscribe之前执行的。
当视图模型只是一个简单属性时,结果如预期:
任何人都知道为什么会发生这种情况?
我真的很难问正确的问题,所以我会试着让我更清楚一下我所追求的是什么。对不起;)
当里面绑定到该输入的observable的“subscribe”函数时,我需要知道输入的值是否有效。
我在订阅函数中使用isValid值 来确定执行是否可以继续(isValid为true)或者执行是否必须停止(isValid为false)。
当输入绑定到ko.foreach中的observable时,isValid的值不会更新,直到 AFTER 执行observable的subscribe函数。这意味着当我需要确定执行是否可以继续或者执行是否必须停止时,我将获得isValid的陈旧值。
< /编辑>
ko.bindingHandlers.numeral = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
},
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var value = ko.utils.unwrapObservable(valueAccessor()),
format = ko.utils.unwrapObservable(allBindingsAccessor().format) || ko.bindingHandlers.numeral.defaultFormat,
formattedValue = Number(value) ? numeral(value).format(format) : value;
$(element).val(formattedValue);
},
defaultFormat: "0,0.00"
};
var viewModel = function(param) {
var self = this;
self.item = ko.observable().extend({ number: true });
self.item.subscribe(function(value) {
$("#log").append("<p>self.item is " + value + " and self.item.isValid is " + self.item.isValid() + "</p>");
});
self.items = ko.mapping.fromJS([]);
ko.mapping.fromJS(param, {
key: function(data) {
return data.CustomerId;
},
create: function(options) {
return new itemViewModel(options.data);
}
}, self.items);
};
var itemViewModel = function(item) {
var self = this;
ko.mapping.fromJS(item, {}, self);
self.InvoiceAmount.extend({ number: true });
self.InvoiceAmount.subscribe(function(value) {
$("#log").append("<p>self.InvoiceAmount is " + value + " and self.InvoiceAmount.isValid is " + self.InvoiceAmount.isValid() + "</p>");
});
}
$(function() {
var vm = new viewModel([{ "InvoiceAmount": 10 }, { "InvoiceAmount": 20 }, { "InvoiceAmount": 30 }, { "InvoiceAmount": 40 }]);
ko.applyBindings(vm);
});
.error {
color: #FF0000;
}
p {
margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/numeral.js/1.5.3/numeral.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.js"></script>
<div>
single item:<br/>
<input type="text" data-bind="numeral: item"/>
</div>
<div>
foreach:<br/>
<table>
<tbody data-bind="foreach: items">
<tr>
<td><input type="text" data-bind="numeral: InvoiceAmount"/></td>
</tr>
</tbody>
</table>
</div>
<div id="log"></div>
答案 0 :(得分:2)
完全修订回复:
依赖订阅顺序很可能是错误的。存在依赖系统的转换状态,在此期间整体状态不一致。该系统旨在达到一致的状态,而不是在每个瞬间都处于一个状态。
让系统有时间达到一致状态的常用技巧是将setTimeout
包裹在代码中,否则可能会在更改中执行。我已经修改了下面的代码来做到这一点,你可以看到报告的状态是正确的。
ko.bindingHandlers.numeral = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
},
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var value = ko.utils.unwrapObservable(valueAccessor()),
format = ko.utils.unwrapObservable(allBindingsAccessor().format) || ko.bindingHandlers.numeral.defaultFormat,
formattedValue = Number(value) ? numeral(value).format(format) : value;
$(element).val(formattedValue);
},
defaultFormat: "0,0.00"
};
var viewModel = function(param) {
var self = this;
self.item = ko.observable().extend({
number: true
});
self.item.subscribe(function(value) {
$("#log").append("<p>self.item is " + value + " and self.item.isValid is " + self.item.isValid() + "</p>");
});
self.items = ko.mapping.fromJS([]);
ko.mapping.fromJS(param, {
key: function(data) {
return data.CustomerId;
},
create: function(options) {
return new itemViewModel(options.data);
}
}, self.items);
};
var itemViewModel = function(item) {
var self = this;
ko.mapping.fromJS(item, {}, self);
self.InvoiceAmount.extend({
number: true
});
self.InvoiceAmount.subscribe(function(value) {
setTimeout(function () {
$("#log").append("<p>self.InvoiceAmount is " + value + " and self.InvoiceAmount.isValid is " + self.InvoiceAmount.isValid() + "</p>");
}, 0);
});
}
$(function() {
var vm = new viewModel([{
"InvoiceAmount": 10
}, {
"InvoiceAmount": 20
}, {
"InvoiceAmount": 30
}, {
"InvoiceAmount": 40
}]);
ko.applyBindings(vm);
});
.error {
color: #FF0000;
}
p {
margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/numeral.js/1.5.3/numeral.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.js"></script>
<div>
single item:
<br/>
<input type="text" data-bind="numeral: item" />
</div>
<div>
foreach:
<br/>
<table>
<tbody data-bind="foreach: items">
<tr>
<td>
<input type="text" data-bind="numeral: InvoiceAmount" />
</td>
</tr>
</tbody>
</table>
</div>
<div id="log"></div>