2012-09-08 15 views
21

Aquí está mi situación. Estoy usando el complemento de mapeo knockout para crear una jerarquía de modelo de vista observable para mí. Mi jerarquía tiene elementos anidados en ella. En un punto particular de la jerarquía, quiero poner un botón Agregar para insertar una nueva copia en blanco de ese elemento en el conjunto observable. El problema es que no puedo decir whateverArray.push (nuevo MyObject()).¿Cómo hago una copia profunda de un objeto knockout que fue creado por el plugin de mapeo

Dado que el complemento de mapeo realmente creó toda la jerarquía para mí, no tengo acceso a "MyObject". Por lo tanto, parece que lo único que puedo hacer para insertar un nuevo elemento es mirar un elemento anterior y copiarlo. Probé la función ko.utils.extend, pero parece que no está haciendo un clon real. Me devuelve un objeto, pero cuando actualizo ese objeto, todavía afecta al objeto original desde el que se copió.

Ver jsFiddle example

Respuesta

37

Puede haber una manera de configurar esto en los ajustes de proyección, pero no acabo de darse cuenta de eso por el momento.

Mientras tanto, puede desasignar el objeto y asignarlo de nuevo para que esencialmente esté haciendo una copia.

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

Ésta será la forma más fácil de hacerlo al igual que cualquier otra biblioteca, "deserializar" y "serialización" de nuevo.


Estaba buscando una buena forma de hacer esto usando las opciones de mapeo y encontré la manera.

De manera predeterminada, el complemento de mapeo tomará las instancias observables del objeto de origen y usará la misma instancia en el objeto de destino. Entonces, en efecto, ambas instancias compartirán los mismos observables (¿error?). Lo que teníamos que hacer era crear un nuevo observable para cada propiedad y copiar los valores.

Afortunadamente, hay una práctica función de utilidad para trazar cada una de las propiedades de un objeto. Luego podemos crear nuestras nuevas instancias observables inicializadas con copias de los valores.

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

Tenga en cuenta que esta será una copia superficial, es probable que tenga que asignar de forma recursiva los objetos si desea una copia en profundidad. Sin embargo, esto solucionará el problema en tu ejemplo.

+0

¡Gracias! Eso parece estar funcionando. – emirhosseini

+0

Sin embargo, todavía me pregunto si existe una forma mejor de nocaut para simplemente hacer un clon real de un objeto que tenga elementos observables. Esto realmente no sería un problema si no estuviese usando el plugin de mapeo ya que yo sería el que crearía cada objeto hijo yo mismo y simplemente podría comenzar uno nuevo directamente en vez de intentar copiar ... – emirhosseini

+0

Ah, yo lo tengo. Estaba en el proceso de darme por vencida y escribir un largo comentario sobre mis hallazgos ... luego tuve una revelación y me di cuenta. –

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

Aquí está mi solución, espero que ayude. En este código, obj sería su objeto viewModel.

Cuestiones relacionadas