【问题标题】:Knockout mapping and bindings淘汰赛映射和绑定
【发布时间】:2014-03-26 05:29:05
【问题描述】:

我在使用映射插件的淘汰赛中遇到了嵌套视图模型的一些问题。我能够重现这个问题,我在这里为它创建了一个小提琴:Fiddle

我已经剥离了实际的视图和视图模型,所以不要期望输出看起来不错,但它会得到消息。这是我的看法:

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

会发生以下情况:

我单击链接 CLICK TO ADD UNIT,并创建了一个 UnitViewModel,对于 UnitMember 数组中的每个元素,由于我是自定义活页夹 (unitMapper),它将使用 UnitMemberViewModel使用。

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

但是,当我调用该方法时,对 observable 的更改会反映在视图中,但对 observableArray 的更改在视图中不可见。详情请查看小提琴。

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

我做了一些观察:

  • observable 上的点击事件不起作用,只有observableArray 上的元素的点击事件。
  • 点击事件中的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)) 上调用 splice 会从视图中移除元素,因此从某种意义上说,self 引用的元素与视图内链接的元素不是同一个对象。但是,为什么它对不是arrayobservable 有效?

我的模型可能存在缺陷,但我看不到它,因此我希望能得到一些帮助。

【问题讨论】:

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


    【解决方案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 的上下文中。

    【讨论】:

    • 完美!我知道我在某处搞砸了绑定,但在此过程中某处“失明”。但是有一个问题:为什么我的绑定对 observable 而不是 observableArray 起作用?我本以为我的绑定设置方式都会失败。
    猜你喜欢
    • 2014-03-20
    • 2012-09-05
    • 1970-01-01
    • 2013-05-27
    • 2012-06-08
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多