【问题标题】:Why does Knockout.js data-bind to checkedValue overwrite observable?为什么 Knockout.js 数据绑定到 checkedValue 会覆盖 observable?
【发布时间】:2014-11-04 22:29:19
【问题描述】:

我在使用淘汰赛映射插件时遇到了问题。 我有一个 ShippingOptions 数组,我使用选中的值将其数据绑定到单选按钮,并将选中的属性设置为我的视图模型上名为 ShippingChoice 的另一个对象。

我有一个计算出的可观察总计,它是我的 SubTotalShippingChoice.Price

的总和

When one of the radio options is selected it correctly sets ShippingChoice to the selected shipping option, but it causes the ShippingChoice to no longer be an observable and breaks my computed total

控制台显示错误“类型错误:数字不是函数”,因为我在我的计算中访问 ShippingChoice().Price。一旦设置了值,它似乎会用一个普通的对象覆盖我的 observable。

我尝试使用自定义映射将运输选项设置为可观察的,但这没有帮助。

Jsfiddle 演示地址: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);

【问题讨论】:

  • 顺便说一句,你的小提琴缺少 updateQty 函数。

标签: javascript knockout.js knockout-mapping-plugin observable


【解决方案1】:

您也可以通过在映射选项中“复制”您的 ShippingOptions 来解决您的问题:

var mapping = {
  'ShippingChoice': {
    create: function (options) {
      return ko.observable(options.data);
    }
  },
  copy: [ 'ShippingOptions' ]
};

这将导致纯对象数组,价格将是数字而不是可观察的。

http://jsfiddle.net/2dv33vor/12/

【讨论】:

    【解决方案2】:

    你几乎拥有它。你的映射对象应该稍微改变一下:

    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 的属性设为可观察的。

    Working demo.

    【讨论】:

      【解决方案3】:

      更改您的 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);
      

      当您在原始代码中将 console.log(value) 添加到 money 绑定处理程序时,您会在做出运输选择后立即看到:

      "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}"
      

      这表明一个 observable 使用 + 运算符连接到一个 non-observable。

      您的Total 函数是唯一可能发生这种情况的地方。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-01
        • 1970-01-01
        • 2012-06-10
        • 2023-03-15
        • 2015-04-16
        • 2012-06-16
        • 2021-12-11
        • 2013-06-09
        相关资源
        最近更新 更多