Knockout.js-更新父视图模型中的数组,在第二个视图模型中使用值

Knockout.js - Updating an array in parent view model, with value in second view model

本文关键字:模型 视图 第二个 js- 更新 Knockout 数组      更新时间:2023-10-24

所以我有两个视图模型,一个包含我使用的数组,该数组将dataList中的每个数据节点绑定到表单,另一个用作每个数据节点的模型。我正试图用来自第二个视图模型的数据更新第一个视图模型中的数组:

HTML

<div data-bind="foreach:mainArray">
    <select data-bind="options: $root.ourTypes, optionsValue: 'ID', optionsText: 'Name', value: $data.OurTypeId"></select>
</div>

JavaScript

var dataList = [        
    { OurTypeId: 4 }, // there are other values here... 
    { OurTypeId: 2 }, // and here...
    { OurTypeId: 3 }  // and here...
];
var ourTypes = [
    { ID:"1", Name:"None", Limit:0 },
    { ID:"2", Name:"Fruits", Limit:5 },
    { ID:"3", Name:"Vegetables", Limit:5 },
    { ID:"4", Name:"Meats", Limit:2 }
];
var myViewModel = new MyViewModel(dataList);
ko.applyBindings(myViewModel);
function MyViewModel(dataList) {
    var self = this;
    self.ourTypes = ourTypes;
    self.mainArray = ko.observableArray([]);
    if (dataList.length > 0) {
        for (var i=0; i<dataList.length; i++) {
            var myDataViewModel = new MyDataViewModel(dataList[i]);
            //alert(myDataViewModel.OurType);
            self.mainArray.push(myDataViewModel);
        } 
    }
}
function MyDataViewModel(vm) {
    var self = this;
    if (vm != null) {                     
        var myType = "";
        for (var i=0; i<ourTypes.length; i++) {
            if (ourTypes[i].ID == vm.OurTypeId)
                myType = ourTypes[i].Name;
        }
        self.OurTypeId = ko.observable(vm.OurTypeId);
        self.OurType = myType;
   } else {
       self.OurTypeId = 0;    
       self.OurType = "";    
   }
   self.OurTypeId.subscribe(function(newValue) {
       var updatedItem = 0;
       var newName = "";
       for (var i=0; i<ourTypes.length; i++) {
          if (ourTypes[i].ID == newValue) {
            self.OurType = ourTypes[i].Name;
            // alert(ourTypes[i].Name);
             updatedItem = i;
          }
       }
   //  I want to do something like this to update "OurType" in mainArray...
   //  var theList = MyViewModel.mainArray();
   //  theList[updatedItem].OurType = self.OurType;
   //  MyViewModel.mainArray(theList);
   });
}

这实际上是一个精简版的代码,只关注"我们的类型",我的fiddle有更多。我使用下拉列表中的ID来指示模型的更改,但随后我必须手动更新类型的实际名称(当ID在我的小提琴中时,你会看到名称不会更新),所以我尝试在.subscribe()函数中这样做,但似乎什么都不起作用。有什么想法吗?

Fiddle:http://jsfiddle.net/navyjax2/ks6nbzp7/

由于OurType的名称应该在更改ID时自动更改,因此这对于计算的可观察对象来说是一项很好的工作:

self.OurType = ko.computed(function() {
    return ko.utils.arrayFirst(ourTypes, function(type) {
        return type.ID == self.OurTypeId();
    }).Name;
});

当一个计算的可观测值运行时,它会注意到被访问的所有其他可观测值——在我们这里的例子中,这只是self.OurTypeId()。这被称为依赖。每当依赖项发生更改时,计算会自动再次运行。

这里,我们使用Knockout辅助函数ko.utils.arrayFirst来迭代ourTypes,并返回其中ID与用户选择的self.OurTypeId()匹配的第一个元素。然后,我们返回该ourType元素的.Name

JSFiddle

请注意,您的if (vm != null) else子句可能存在问题:您在其中设置的值是不可观察的。

self.OurTypeId = 0;

这意味着vmnullMyDataViewModel将被破坏——Knockout将把<select>绑定到一个普通的、不可观察的"0",并且永远不会再更新。

此外,一次您使self.SlotPosition成为可观测的,另一次您则使其成为可观测阵列。

最好将属性初始化为可观察的一次,然后只更新其值:

function MyDataViewModel(vm) {
    var self = this;
    this.SlotPosition = ko.observable();
    this.OurTypeId    = ko.observable();
    if (vm) {
        this.SlotPosition(vm.SlotPosition);
        this.OurTypeId(vm.OurTypeId);
    }
    this.OurType = ko.computed(function() {
        if (!self.OurTypeId()) {
            return;
        }
        return ko.utils.arrayFirst(ourTypes, function(type) {
            return type.ID == self.OurTypeId();
        }).Name;
    });
}