Reputation: 209
i want to clone/(deep)copy an item inside an knockoutjs observableArray.
I can't find any information in the net regarding this problem. Everybody want's to just clone the hole array ;)
Here is the jsfiddle: http://jsfiddle.net/drchef/dCHMC/1/
there you can see, i'm using a deepcopy method I found on SO.
this.cloneLine = function() {
//This 2 lines is what i found on SO. Should work, but doesn not :(
//cloning the second line (sry hardcoded...)
var lastLine = this.lines()[1];
this.lines.push(jQuery.extend(true, {}, lastLine));
};
In the viewmodel-output you can see the copy is working...but internally the new item and the cloned item reference still to the same values. If you change a value in the new line, it is also changed in the original line.
Background: I have a grid of inputs and if the user is in the last line and hits "enter" in want a new line + the same data of the last line
I don't want to write a method or something witch is cloning every single data. On every change of the vm, I have to update the mapping. ;(
thank you
Upvotes: 3
Views: 3257
Reputation: 10942
You need to unwrap the observables in the Line viewmodel. You can do this using the ko.toJS
utility method. Demo
function Line(line) {
this.a = ko.observable(line && line.a);
this.b = ko.observable(line && line.b);
this.c = ko.observable(line && line.c);
};
var ViewModel = function() {
var self = this;
this.lines = ko.observableArray([]);
this.cloneLine = function(line) {
var l = new Line(ko.toJS(line));
self.lines.push(l);
};
this.cloneLastLine = function() {
var lines = self.lines(),
line = lines[lines.length - 1];
self.cloneLine(line);
};
}
var model = new ViewModel();
//Initial Data
model.lines.push(new Line({ a: 0, b: 1, c: 2}));
model.lines.push(new Line({ a: 2, b: 1, c: 0}));
ko.applyBindings(model);
Upvotes: 3
Reputation: 8418
To make a copy with different references in Knockout you really need to create a copy...literally. With your method, you were never really breaking any chains to the existing knockout binding. As you'll see in the update to your fiddle below, you need to drop the 'lastLine' to a flat JS object then create a new 'line' object and pass it into your observable array.
this.cloneLine = function() {
var lastLine = ko.toJS(this.lines()[1]);
this.lines.push(new line(lastLine.a, lastLine.b, lastLine.c));
};
Upvotes: 1