2012-09-08 10 views
21

Ecco il mio scenario. Sto utilizzando il plug-in di mappatura a eliminazione diretta per creare una gerarchia viewmodel osservabile per me. La mia gerarchia contiene elementi nidificati. In un punto particolare della gerarchia voglio inserire un pulsante Aggiungi per inserire una nuova copia vuota di quell'elemento nel campo observablearray. Il problema è che non posso semplicemente dire qualunque Array.push (nuovo MyObject()).Come faccio una copia profonda di un oggetto knockout che è stato creato dal plugin di mappatura

Poiché il plug-in di mappatura ha effettivamente creato l'intera gerarchia per me, non ho accesso a "MyObject". Quindi sembra che l'unica cosa che posso fare per inserire un nuovo oggetto è guardare un articolo precedente e copiarlo. Ho provato la funzione ko.utils.extend, ma non sembra che stia facendo un vero clone. Mi restituisce un oggetto, ma quando aggiorno quell'oggetto influisce ancora sull'oggetto originale da cui è stato copiato.

Vedi jsfiddle example

risposta

37

Ci potrebbe essere un modo per impostare questa funzione nelle impostazioni di mappatura, ma non riesco a capire che fuori appena ancora.

Nel frattempo, è possibile semplicemente annullare la mappatura dell'oggetto e mapparlo indietro in modo da fare essenzialmente una copia.

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

questo sarà il modo più semplice per farlo, proprio come qualsiasi altra libreria, "deserializzare" e "serializzare" di nuovo.


Stavo cercando un modo piacevole per farlo utilizzando le opzioni di mappatura e trovato un modo.

Per impostazione predefinita, il plug-in di mappatura prende le istanze osservabili dall'oggetto di origine e utilizza la stessa istanza nell'oggetto di destinazione. Quindi, in effetti, entrambe le istanze condivideranno gli stessi osservabili (bug?). Quello che dovevamo fare era creare un nuovo osservabile per ogni proprietà e copiare i valori.

Fortunatamente, esiste una pratica funzione di utilità per mappare ciascuna proprietà di un oggetto. Possiamo quindi creare le nostre nuove istanze osservabili inizializzate con copie dei valori.

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

Nota che questa sarà una copia, probabilmente dovrete per mappare in modo ricorsivo gli oggetti se si desidera una copia profonda. Ciò tuttavia risolverà il problema nel tuo esempio.

+0

Grazie! Sembra funzionare. – emirhosseini

+0

Tuttavia, mi chiedo ancora se ci sia un modo migliore in KO per fare semplicemente un vero clone di un oggetto che contiene degli osservabili. Questo non sarebbe un problema se non usassi il plug-in di mappatura da allora sarei io a creare personalmente ogni oggetto figlio e potrei semplicemente aggiungerne uno direttamente piuttosto che provare a copiare ... – emirhosseini

+0

Ah, I fatto. Stavo per arrendermi e scrivere un lungo commento sulle mie scoperte ... poi ho avuto una rivelazione e l'ho capito. –

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

Ecco la mia soluzione, spero che aiuti. In questo codice, obj sarebbe il tuo oggetto viewModel.

Problemi correlati