2012-09-08 38 views
21

這是我的場景。我正在使用knockout貼圖插件爲我創建一個可觀察的視圖模型層次結構。我的層次結構中嵌套了元素。在層次結構中的某個特定點上,我想要添加一個Add按鈕以在observablearray中插入該元素的新空白副本。問題是我不能說什麼Array.push(新的MyObject())。如何製作由映射插件創建的挖空物體的深層副本

由於映射插件實際上爲我創建了整個層次結構,因此我無法訪問「MyObject」。所以看起來我能做的只有插入一個新項目才能看到以前的項目並複製它。我嘗試了ko.utils.extend函數,但似乎並沒有做出實際的克隆。它給我一個對象,但是當我更新這個對象時,它仍然會影響它從中複製的原始對象。

見的jsfiddle example

回答

37

有可能是在映射設置來設置此一方式,但我不能完全明白這一點,只是還沒有。

與此同時,您可以取消映射對象並將其映射回來,以便實質上製作副本。

var newJob = ko.mapping.fromJS(ko.mapping.toJS(job)); 

這將是最簡單的方法,就像任何其他庫一樣,「反序列化」和「序列化」再次。


我正在尋找一種很好的方式來使用映射選項來完成此操作,並找到了一種方法。

默認情況下,映射插件將從源對象中獲取可觀察的實例,並在目標對象中使用相同的實例。所以實際上,兩個實例將共享相同的觀察對象(bug?)。我們需要做的是爲每個屬性創建一個新的observable並複製這些值。

幸運的是,有一個方便的實用功能可以繪製出對象的每個屬性。然後,我們可以創建新的可觀察實例,並使用值的副本進行初始化。

// Deep copy 
var options = { 
    create: function (options) { 
     // map each of the properties 
     return ko.mapping.visitModel(options.data, function (value) { 
      // create new instances of observables initialized to the same value 
      if (ko.isObservable(value)) { // may want to handle more cases 
       return ko.observable(value); 
      } 
      return value; 
     }); 
    } 
}; 
var newJob = ko.mapping.fromJS(job, options); 

請注意,這將是一個淺拷貝,如果您想要深度複製,您可能必須遞歸映射對象。這將解決您的示例中的問題。

+0

謝謝!這似乎工作。 – emirhosseini

+0

但是我仍然想知道是否有一種更好的方法可以在淘汰賽中簡單地製作一個可觀察對象的真實克隆。這並不是真正的問題,如果我不使用映射插件,那麼我將自己創建每個子對象,我可以直接從一個新的直接而不是試圖複製... – emirhosseini

+0

啊,我得到它了。我正在放棄並撰寫關於我的發現的長篇評論......然後我有了一個啓示並找出了它。 –

6
ko.utils.clone = function (obj) { 
    var target = new obj.constructor(); 
    for (var prop in obj) { 
     var propVal = obj[prop]; 
     if (ko.isObservable(propVal)) { 
      var val = propVal(); 
      if ($.type(val) == 'object') { 
       target[prop] = ko.utils.clone(val); 
       continue; 
      } 
      target[prop](val); 
     } 
    } 
    return target; 
}; 

這是我的解決方案,希望它有幫助。在此代碼中,obj將是您的viewModel對象。