1

我使用映射插件在挖空中嵌套视图模型有一些问题。我能够重新创建这个问题,并且我在这里创建了一个小提琴:Fiddle敲除映射和绑定

我已经分解了实际的视图和viewmodel,所以不要指望输出看起来不错,但它会得到消息accros。这是我的看法:

<div data-bind="foreach: $root.selectedArmy().Units"> 
    <div class="unitoverview"> 
     <!-- ko foreach: UnitMembers--> 
     <div class="member"> 
      <div> 
       <span class="name" data-bind="text: Name, click: $parent.RemoveTest"></span> 
      </div> 
      <div data-bind="foreach: test"> 
       <span data-bind="text:$data, click: $parent.RemoveTest"></span> 
      </div> 
      <h1 data-bind="text: test2"></h1> 
     </div> 
     <!-- /ko --> 
    </div> 
</div> 
<span data-bind="click:AddUnit">CLICK TO ADD UNIT</span> 

这是我的模型:

var armymaker = armymaker || {}; 

var unitMapping = { 
    'UnitMembers': { 
    create: function (options) { 
     return new UnitMemberViewModel(options.data); 
    } 
    } 
}; 

var UnitViewModel = function (unit) { 
    var self = this; 
    self.Name = ko.observable("unitname"); 
    self.UnitDefinitionId = ko.observable(unit.Id); 
    ko.mapping.fromJS(unit, {}, self); 
}; 

var UnitMemberViewModel = function (unitmemberdefinition) { 
    var self = this; 

    self.test = ko.observableArray([ko.observable('TEST'), ko.observable('TEST2')]); 
    self.test2 = ko.observable('TEST1'); 
    self.RemoveTest = function() { 
    self.test.splice(0,1); 
    self.Name('BUGFACE'); 
    self.test2('OKI!!'); 
    }; 
    ko.mapping.fromJS(unitmemberdefinition, {}, self); 
}; 

var ViewModel = function() { 
    var self = this; 
    self.showLoader = ko.observable(false); 
    self.newArmy = ko.observable({}); 
    self.unitToAdd = ko.observable(null); 
    self.selectedArmy = ko.observable({ Template: ko.observable(''), Units: ko.observableArray() }); 
    self.AddUnit = function() { 
    var data = {'Name': 'My name', 'UnitMembers': [ 
     { 'Name': 'Unitname1' } 
    ] }; 
    self.unitToAdd(new UnitViewModel((ko.mapping.fromJS(data, unitMapping)))); 
    self.selectedArmy().Units.push(self.unitToAdd()); 
    self.unitToAdd(null); 
    }; 
}; 

armymaker.viewmodel = new ViewModel(); 
ko.applyBindings(armymaker.viewmodel); 

什么情况如下:

我点击链接点击即可添加单元,以及创建一个UnitViewModel,并且对于UnitMember阵列中的每个元素,它将使用UnitMemberViewModel,因为我正在使用自定义联编程序(unitMapper)。

这一切似乎工作正常。但是在最内层的视图模型中,我向数据模型添加了一些字段。我叫他们test这是一个observableArraytest2这是一个普通的observable。我还创建了一个名为RemoveTest的方法,该方法在代表test2的跨度和代表数组test中的每个元素的foreach的范围内都被绑定。

但是,当我调用该方法时,视图中反映了对observable的更改,但在视图中未显示对observableArray的更改。检查小提琴的细节。

是否有任何原因导致在视图中看不到obsArray的更改,但是对普通observable的更改将会如何?

我已经取得了一些意见:

  • observable click事件不工作,只在observableArray元素click事件。
  • 看来,click事件中的self与实际的viewmodel不匹配。如果我去self.test.splice(0,1)视图中没有任何反应,但self.test.splice只包含该命令之后的一个元素。但是如果我遍历基本视图模型(armymaker.viewmodel.Units()[0].UnitMembers()[0].test)仍然包含两个元素。
  • 在遍历视图模型(armymaker.viewmodel.Units()[0].UnitMembers()[0].test.splice(0,1))上调用拼接会从视图中移除该元素,因此它在某种程度上似乎是由self引用的元素与视图内链接的元素不同。但是,那么为什么它的observable不是array

我的模型可能有一个缺陷,但我看不到它,所以我将不胜感激这里的一些帮助。

回答

1

你基本上是“双映射”。

先用

self.unitToAdd(new UnitViewModel((ko.mapping.fromJS(data, unitMapping)))); 

UnitViewModel内第二次:

ko.mapping.fromJS(unit, {}, self); 

其中unit已经是ko.mapping创建完整的“UnitViewModel”,这种双重映射导致您的所有问题。

要修复它,你只需要删除的第一个映射:

self.unitToAdd(new UnitViewModel(data)); 
self.selectedArmy().Units.push(self.unitToAdd()); 
self.unitToAdd(null); 

,并使用UnitViewModel内的映射选项:

var UnitViewModel = function (unit) { 
    var self = this; 
    self.Name = ko.observable("unitname"); 
    self.UnitDefinitionId = ko.observable(unit.Id); 
    ko.mapping.fromJS(unit, unitMapping, self); 
}; 

演示JSFiddle

的SideNote修复“可观测的单击事件不工作”的问题,你只需要删除$parent

<span class="name" data-bind="text: Name, click: RemoveTest"></span> 

,因为你已经在一个UnitMemberViewModel的情况下。

+0

完美!我知道我在某处弄乱了绑定,但在这个过程的某个地方变得“失明”。但有一个问题:为什么我的绑定工作可观察而不是可观察的数组?我会认为这会对我的约束力建立的方式失败。 –