当Knockout指向... knockout-3.4.0.js中的非调试版本时,this jsbin中的代码似乎正常工作,但调试版本位于... knockout-3.4.0 .debug.js有绑定错误。
要重现,请将44.11111之类的小数添加到其中一个文本框中。正确舍入到小数点后2位。添加更多小数,再次生成数字44.11111。在第一次更新后,精度不会更新到2个小数位,即:扩展器未触发,数字仍为44.11111。
此版本中是否有错误?可能与缩小?
https://jsbin.com/sehibihoka/edit?html,css,js,output
ko.extenders.newnumeric = function(target, precision) {
//create a writable computed observable to intercept writes to our observable
var result = ko.pureComputed({
read: target, //always return the original observables value
write: function(newValue) {
var current = target(),
roundingMultiplier = Math.pow(10, precision),
newValueAsNum = isNaN(newValue) ? 0 : parseFloat(+newValue),
valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
//only write if it changed
if (valueToWrite !== current) {
target(valueToWrite);
} else {
//if the rounded value is the same, but a different value was written, force a notification for the current field
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
}).extend({
notify: 'always'
});
//initialize with current value to make sure it is rounded appropriately
result(target());
//return the new computed observable
return result;
};
var data = {
groups: [{
id: 1,
groupSelected: true,
numbers: [{
num: 33.00
}, {
num: 44.11
}, {
num: 2.5
}, {
num: 11.5
}]
}, {
id: 2,
groupSelected: true,
numbers: [{
num: 22
}, {
num: 2
}]
}, {
id: 3,
groupSelected: false,
numbers: [{
num: 1.25
}, {
num: 66.66
}]
}]
};
var mapping = {
'groups': {
create: function(options) {
return new groupModel(options.data);
}
}
};
var numberMapping = {
'numbers': {
create: function(options) {
return new numberModel(options.data);
}
}
};
var groupModel = function(data) {
var self = this;
ko.mapping.fromJS(data, numberMapping, self);
self.GroupTotal = ko.pureComputed(function() {
var sum = 0;
ko.utils.arrayForEach(self.numbers(), function(r) {
sum += (+r.num());
});
return sum.toFixed(2);
});
};
var numberModel = function(data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
self.num = self.num.extend({
newnumeric: 2
});
};
var viewModel = ko.mapping.fromJS(data, mapping);
viewModel.GrandTotal = ko.pureComputed(function() {
var sum = 0;
// + is unary plus operator. alternate version is parseInt()
ko.utils.arrayForEach(viewModel.groups(), function(r) {
sum += (+r.GroupTotal());
});
return sum.toFixed(2);
});
// console.log(ko.mapping.toJS(viewModel));
ko.applyBindings(viewModel);
.divBlock {
padding: 5px;
background-color: #ccc;
}
.spanBlock {
padding: 5px;
margin: 5px;
background-color: white;
}
.inputText {
margin: 5px;
width: 50px;
}
<html>
<head>
<script src="https://code.jquery.com/jquery-1.12.3.js" integrity="sha256-1XMpEtA4eKXNNpXcJ1pmMPs8JV+nwLdEqwiJeCQEkyc=" crossorigin="anonymous"></script>
<script src="https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.4.0.debug.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
</head>
<body>
<div class="divBlock" data-bind="foreach:groups">
<div class="spanBlock">
<div>
<span data-bind="text: 'Id: ' + id() "></span>
</div>
<div data-bind="text: 'Group Total: ' + GroupTotal()"></div>
<p data-bind="foreach:numbers">
<input type="text" data-bind="value: num" class="inputText" />
</p>
</div>
</div>
<div data-bind="text: GrandTotal"></div>
</body>
</html>