【问题标题】:KnockoutJS - ViewModel Grandparent - Parent - Child using ko.computed to access Parent/Grandparent ValueKnockoutJS - ViewModel Grandparent - Parent - Child 使用 ko.computed 访问父/祖父值
【发布时间】:2015-03-23 00:19:32
【问题描述】:

我在剔除和剔除映射、CustomerViewModel、WorkOrderViewModel 和 RepairViewModel 中设置了祖父、父、子 ViewModel 关系。

我想在子级中设置一个子级 ko.computed 值,该值占用 RepairViewModel 中的小时数,并将其乘以 WorkOrderView 模型中的 Rate。

在 RepairViewModel 我有这样的代码:

self.RepairCost = ko.computed(function () {

             return (self.Hours() * self.parent.LabourChargeCost()).toFixed(2);
     });

有没有办法获取父级的值?

非常感谢!

这是我正在使用的 JS 代码(简化):

var workOrderMapping = {
    'WorkOrders': {
        key: function (workOrders) {
            return ko.utils.unwrapObservable(workOrders.WorkOrderId);
        },
        create: function (options) {
            return new WorkOrderViewModel(options.data);
        }
    },

    'Repairs': {
        key: function (repairs) {
            return ko.utils.unwrapObservable(repairs.RepairId);
        },
        create: function (options) {
            return new RepairViewModel(options.data);
        }
    }
};


RepairViewModel = function (data) {
    var self = this;
    ko.mapping.fromJS(data, workOrderMapping, self);

     self.RepairCost = ko.computed(function () {    
         return (self.Hours() * self.parent.LabourChargeCost()).toFixed(2);
     })

    ;
}

WorkOrderViewModel = function (data) {
    var self = this;
    ko.mapping.fromJS(data, workOrderMapping, self);

}

CustomerViewModel = function (data) {
    var self = this;
    ko.mapping.fromJS(data, workOrderMapping, self);

    self.save = function () {
        //alert(ko.toJSON(self));
        $.ajax({
            url: "/Customers/Save/",
            type: "POST",
            data: ko.toJSON(self),
            contentType: "application/json",
            success: function (data) {
                //alert("succ");
                //alert(data.customerViewModel);
                // if (data.customerViewModel != null) {
                //alert("succ2");
                new PNotify({
                    title: 'Saved',
                    text: 'Record saved successfully',
                    type: 'success',
                    styling: 'bootstrap3'

                });


                ko.mapping.fromJS(data.customerViewModel, workOrderMapping, self);

                if (data.newLocation != null)
                    window.location = data.newLocation;
            },


        });
    };
}

【问题讨论】:

    标签: javascript jquery mvvm knockout.js


    【解决方案1】:

    除非您将父级传递给子级并保留引用,否则您无法访问子级模型中的父级。

    过去对我来说更好的方法是将值传递给子模型,然后在父模型中添加订阅以在值更改时更新子模型。

    function Parent(){
      var self = this;
      self.someValue = ko.obserable();//init if you need to
      self.children = [new Child(self.someValue())]
    
      self.someValue.subscribe(function(value){
          for(var i = 0;i<self.children.length;i++){
              self.children[i].parentValue(value);
          }
      });
    }
    function Child(value){
        var self = this;
        self.parentValue = ko.observable(value);
    }
    

    【讨论】:

      【解决方案2】:

      不幸的是,您不能这样做,这不是 Knockout 而是 JS 的限制:您无法从对象属性中访问父上下文。 正如@GrayTower 所提到的,您可以做的是将您的父母作为参数传递,但这对我来说,感觉有点像黑客(虽然我承认有时会使用它)。

      您还可以在绑定视图模型之前从父视图模型内部或外部修改子视图模型。我不太了解您提供的代码中的属性流,但我希望一个较小的测试用例能够满足您的需求:http://jsfiddle.net/kevinvanlierde/507k237y/。假设我们有以下父子视图模型:

      // symbolizes an employee
      function ChildVM(name, hoursWorked) {
          var self = this, parent;
          this.name = name;
          this.hoursWorked = hoursWorked;
      }
      // symbolizes a payment system
      function MasterVM() {
          var self = this;
          this.rate = 25; // dollars/hour
          this.employees = [
              new ChildVM('Chris',16),
              new ChildVM('Cagle',32)
          ];
      }
      var app = new MasterVM(), 
          view = document.getElementsByTagName('table')[0];
      

      我们希望为employees 中的每个ChildVM 添加一个属性payout,这将使用来自MasterVMrate 和来自ChildVMhoursWorked,即ko.computed。您可以简单地将函数粘贴到 MasterVM 构造函数中,如下所示:

        ko.utils.arrayForEach(self.employees, function(i) {
            i.payout = ko.computed(function() {
                return i.hoursWorked*self.rate;
            });
        });
      

      或者你可以把它变成一个方法并在调用ko.applyBindings之前调用它:

          this.initEmployees = function() {
              ko.utils.arrayForEach(self.employees, function(i) {
                  i.payout = ko.computed(function() {
                      return i.hoursWorked*self.rate;
                  });
              });
          }
          app.initEmployees();
          ko.applyBindings(app, view);
      

      或者您甚至可以构建一个 applyBindings 包装器,它在绑定视图和模型之前执行“callBefore”(参见 AJAX callbacks),如下所示:

      function initVM(VM, callbefore, element) {
          callbefore(VM);
          ko.applyBindings(VM, element);
      }
      initVM(app, function(vm) {
         ko.utils.arrayForEach(vm.employees, function(i) {
           i.payout = ko.computed(function() {
              return i.hoursWorked*vm.rate;
           });
         });
      },view);
      

      fiddle
      注意:使用ko.mapping.fromJSconverts 所有值到可观察值,而当你的值不需要更新你不需要 observables,你可以使用纯 JS 值/对象。

      【讨论】:

        猜你喜欢
        • 2015-03-25
        • 1970-01-01
        • 1970-01-01
        • 2011-06-09
        • 1970-01-01
        • 2012-04-26
        • 1970-01-01
        • 1970-01-01
        • 2011-08-17
        相关资源
        最近更新 更多