Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

knockoutjs: cloning an observableArray-Object

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

like image 803
user3796786 Avatar asked Feb 17 '26 10:02

user3796786


2 Answers

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);
like image 96
Douglas Ludlow Avatar answered Feb 18 '26 22:02

Douglas Ludlow


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.

http://jsfiddle.net/dCHMC/2/

this.cloneLine = function() {
    var lastLine = ko.toJS(this.lines()[1]);
    this.lines.push(new line(lastLine.a, lastLine.b, lastLine.c));
};
like image 21
beauXjames Avatar answered Feb 18 '26 22:02

beauXjames



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!