我在使用映射插件的淘汰赛中遇到嵌套视图模型的问题。我能够重现这个问题,我在这里创造了一个小提琴: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
数组中的每个元素,由于自定义绑定({1}},它将使用UnitMemberViewModel
{1}})我正在使用。
这个似乎可以正常工作。但是在最里面的视图模型中,我向datamodel添加了一些字段。我称他们为unitMapper
test
,observableArray
为普通test2
。我还创建了一个名为observable
的方法,该方法在视图中绑定到表示RemoveTest
的span,以及test2
中表示数组foreach
的每个元素的span。 }}
但是,当我调用该方法时,对test
的更改会反映在视图中,但在视图中看不到observable
的更改。检查小提琴是否有详细信息。
是否有任何原因导致observableArray
的更改在视图中不可见,但对普通obsArray
的更改会是什么?
我做了一些观察:
observable
上的点击事件不起作用,只有observable
上元素的点击事件。observableArray
视图中没有任何反应,但self.test.splice(0,1)
在该命令后只包含一个元素。但是,如果我遍历基本视图模型(self.test.splice
)仍然包含两个元素。armymaker.viewmodel.Units()[0].UnitMembers()[0].test
)上调用splice会从视图中删除元素,因此在某种程度上,self引用的元素与视图中链接的元素不同。但是,为什么它适用于不是armymaker.viewmodel.Units()[0].UnitMembers()[0].test.splice(0,1)
的{{1}}?我的模型可能存在缺陷,但我看不到它,所以我会感激一些帮助。
答案 0 :(得分: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修复“observable上的点击事件不起作用”问题,您只需删除$parent
:
<span class="name" data-bind="text: Name, click: RemoveTest"></span>
因为您已经在一个UnitMemberViewModel
的上下文中。