Knockout-Validation
Knockout-Validation copied to clipboard
isValid reporting incorrectly when bound inside ko.foreach
When using knockout.validation the isValid property will incorrectly report its status but only when it is "inside" a ko.foreach.
Using the code snippet below, if you run and enter the following values (q,z,10) in the same textbox,you will get the following output:
- self.InvoiceAmount is q and self.InvoiceAmount.isValid is true
- self.InvoiceAmount is z and self.InvoiceAmount.isValid is false
- self.InvoiceAmount is 10 and self.InvoiceAmount.isValid is false
As you can see, the validation rule is for a number and q should not report true as well as 10 should not report false.
It appears the order of execution is messed up because InvoiceAmount.subcribe is executed prior to InvoiceAmount.isValid.subscribe.
When the view model is just a simple property, the results are as expected:
- self.item is q and self.item.isValid is false
- self.item is z and self.item.isValid is false
- self.item is 10 and self.item.isValid is true
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);
});
<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>
I also submitted this to stack overflow hoping someone could help me out and there is a working snippet:
http://stackoverflow.com/questions/33194218/when-using-knockout-validation-isvalid-reporting-incorrectly-when-bound-inside
Thanks!
Not sure if you'd tried, but knockout 3.4.0 is available, can you try with that?