KnockoutJS - ViewModel祖父母 - 父母 - 使用ko.computed访问父/祖父母值的孩子

时间:2015-01-23 21:06:03

标签: javascript jquery mvvm knockout.js

我在淘汰赛和淘汰赛映射,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;
            },


        });
    };
}

2 个答案:

答案 0 :(得分:0)

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

过去对我有用的是将值传递给子模型,然后在父级中添加subscribe以在更改值时更新子级。

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);
}

答案 1 :(得分:0)

不幸的是你无法做到这一点,它不是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];

我们希望为payout中的每个ChildVM添加一个属性employeesrateMasterVMhoursWorked结合使用ChildVM来自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

或者您甚至可以构建一个callbacks包装器,它在绑定视图和模型之前执行'callBefore'(cf。&lt; =&gt; AJAX 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); ),如下所示:

ko.mapping.fromJS

<强> fiddle
注意:使用{{1}}将所有值转换为observable,而当您的值不需要更新时,您不需要observable,您可以使用纯JS值/ objects。