淘汰赛映射和绑定

时间:2014-02-24 13:48:48

标签: javascript knockout.js knockout-mapping-plugin ko.observablearray

我在使用映射插件的淘汰赛中遇到嵌套视图模型的问题。我能够重现这个问题,我在这里创造了一个小提琴: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 testobservableArray为普通test2。我还创建了一个名为observable的方法,该方法在视图中绑定到表示RemoveTest的span,以及test2中表示数组foreach的每个元素的span。 }}

但是,当我调用该方法时,对test的更改会反映在视图中,但在视图中看不到observable的更改。检查小提琴是否有详细信息。

是否有任何原因导致observableArray的更改在视图中不可见,但对普通obsArray的更改会是什么?

我做了一些观察:

  • observable上的点击事件不起作用,只有observable上元素的点击事件。
  • 似乎click事件中的self与实际的viewmodel不匹配。如果我去observableArray视图中没有任何反应,但self.test.splice(0,1)在该命令后只包含一个元素。但是,如果我遍历基本视图模型(self.test.splice)仍然包含两个元素。
  • 在遍历的viewmodel(armymaker.viewmodel.Units()[0].UnitMembers()[0].test)上调用splice会从视图中删除元素,因此在某种程度上,self引用的元素与视图中链接的元素不同。但是,为什么它适用于不是armymaker.viewmodel.Units()[0].UnitMembers()[0].test.splice(0,1)的{​​{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的上下文中。