为什么Knockout.js数据绑定到checkedValue会覆盖observable
Why does Knockout.js data-bind to checkedValue overwrite observable?
我在使用淘汰映射插件时遇到了一个问题。我有一个ShippingOptions数组,我使用选中的值将其数据绑定到单选按钮,其中选中的属性设置为视图模型上名为ShippingChoice的另一个对象。
我有一个计算的可观察总额,它是我的SubTotal和ShippingChoice的总和。价格
当选择其中一个单选选项时,它会正确地将ShippingChoice设置为所选的运输选项,但会导致ShippingChoice不再是可观察的,并破坏我计算的总
控制台显示错误"类型错误:数字不是函数",因为我正在访问我的计算中的ShippingChoice().Price。一旦设置了值,它似乎会用一个普通对象覆盖我的可观察对象。
我试图使用自定义映射将Shipping选项设置为可观察的,但这没有帮助。
Jsfidle演示:http://jsfiddle.net/on3al/2dv33vor/9/
任何见解或建议都会得到极大的反响。我对这件事太头疼了。
HTML
<!-- ko foreach: ShippingOptions -->
<div class="radio">
<input type="radio" name="optionsRadios"
data-bind="checkedValue: $data ,checked: $root.ShippingChoice" />
<span data-bind="text: Carrier"></span>
<span data-bind="text: Service"></span>
<span data-bind="money: Price"></span>
</div>
<!-- /ko -->
</div>
<div class="col-xs-4">
<h5 class="text-right">Subtotal <strong data-bind="money: SubTotal"></strong></h5>
<h5 class="text-right" data-bind="money: ShippingChoice().Price">Shipping </h5>
<h4 class="text-right">Total <strong data-bind="money: Total"></strong></h4>
</div>
Javascript
var mapping = {
'ShippingChoice': {
create: function (options) {
return ko.observable(options.data);
}
}
};
CartViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, mapping, self);
self.SubTotal = ko.computed(function () {
var subTotal = 0;
for (var i = 0; i < self.Items().length; i++) {
var item = self.Items()[i];
subTotal += item.Quantity() * item.Product.Price();
}
return subTotal;
}, self);
self.Total = ko.computed(function () {
return self.SubTotal()+ self.ShippingChoice().Price;
}, self);
self.decreaseQty = function (item) {
var currQty = item.Quantity();
if (currQty > 0) {
item.Quantity(currQty - 1);
}
self.updateQty(item);
};
self.increaseQty = function (item) {
var currQty = item.Quantity();
item.Quantity(currQty + 1);
self.updateQty(item);
};
};
ko.bindingHandlers.money = {
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
var positions = 2;
var formattedValue = value.toFixed(positions);
var finalFormatted = '$' + formattedValue;
ko.bindingHandlers.text.update(element, function () {
return finalFormatted;
});
},
defaultPositions: 2,
};
var cartViewModel = new CartViewModel({
"$id": "1",
"Id": "540eb73cff622605c4f45b39",
"Items": [{
"$id": "2",
"Product": {
"$id": "3",
"Status": "In Stock",
"Price": 19.99,
"QuantityInStock": 12,
"Brand": "Dummy Brand",
"Weight": 8.0,
"Width": 12.0,
"Length": 14.0,
"Height": 3.0,
"UrlSlug": "dummy-slug",
"Title": "Dummy Product",
},
"Quantity": 7,
}],
"Country": "CA",
"PostalCode": null,
"ShippingOptions": [{
"$id": "4",
"Carrier": "USPS",
"Price": 22.1,
"Service": "FirstClassPackageInternationalService"
}, {
"$id": "5",
"Carrier": "USPS",
"Price": 32.85,
"Service": "PriorityMailInternational"
}, {
"$id": "6",
"Carrier": "USPS",
"Price": 46.96,
"Service": "ExpressMailInternational"
}],
"ShippingChoice": {
"$id": "7",
"Carrier": "",
"Price": 8.0,
"Service": ""
}
});
ko.applyBindings(cartViewModel);
您也可以通过在映射选项中"复制"ShippingOptions来解决问题:
var mapping = {
'ShippingChoice': {
create: function (options) {
return ko.observable(options.data);
}
},
copy: [ 'ShippingOptions' ]
};
它将产生一个简单的对象数组,并且价格将是数字而不是可观测值。
http://jsfiddle.net/2dv33vor/12/
你几乎做到了。你的映射对象应该稍微改变一下:
var mapping = {
'ShippingChoice': {
create: function (options) {
return ko.observable(ko.mapping.fromJS(options.data));
}
}
};
在你看来,模型是:
...
self.Total = ko.computed(function () {
return self.SubTotal()+ self.ShippingChoice().Price(); // I've added () to the Price, since it's an observable now.
}, self);
问题是,当你的ShippingOptions数组被映射时,它的所有属性都是可观察的。所以你应该让你的ShippingChoice的属性也是可观测的。
工作演示
更改从计算的Total
self.Total = ko.computed(function () {
return self.SubTotal() + self.ShippingChoice().Price;
}, self);
至:
self.Total = ko.computed(function () {
return ko.unwrap(self.SubTotal) + ko.unwrap(self.ShippingChoice().Price);
}, self);
当您在原始代码中向money
绑定处理程序添加console.log(value)
时,您一做出发货选择就会看到:
"307.65000000000003function d(){if(0<
arguments.length)return d.Pa(c,arguments[0])&&(d.X(),c=arguments[0],d.W()),this;a.k.Jb(d);return c}"
这表明用+
算子将可观测项连接到不可观测项。
您的Total
函数是唯一可能发生这种情况的地方。
- 在循环中分配json值时,值被覆盖
- 谷歌地图固定位置覆盖
- 只覆盖箭头键滚动事件
- JQuery覆盖不更改单选选项
- 如何覆盖锚点元素's href目标,并在我点击转到目标javascript时删除其他错误
- 将添加一个相同类型的事件附加或覆盖以前添加的具有相同名称的事件
- 传单中如何在更改基层时启用/禁用覆盖层
- 点击(右键点击)使用传单地图库获取图像覆盖的像素坐标
- HTML/CSS-用于拖放的全页面覆盖
- 让javascript知道epub3电子书中何时播放媒体覆盖
- 覆盖函数中的函数
- 无法覆盖CSS伪元素:before
- 如何覆盖原型中的事件侦听器
- 覆盖在赢得'不允许点击下面的标记,谷歌地图api v3
- 如何覆盖主干中的extend方法
- jQuery无法处理覆盖
- qoxdoo的代码覆盖工具
- 像createComment这样的各种自定义变量名在内联javascript中被覆盖,但在外部js中没有.为什么?
- javascript函数将数据添加到屏幕,但随后被另一个函数覆盖
- 为什么Knockout.js数据绑定到checkedValue会覆盖observable