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

完美!我知道我在某處弄亂了綁定,但在這個過程的某個地方變得「失明」。但有一個問題:爲什麼我的綁定工作可觀察而不是可觀察的數組?我會認爲這會對我的約束力建立的方式失敗。 –