Alex
Alex

Reputation: 38529

Cloning an object with Knockout that has an observable array

I have a view model called ProductsViewModel This contains an observableArray of ProductViewModel

A ProductViewModel also contains an observableArray - of ProductPriceViewModel

One feature I have is that I can duplicate a ProductViewModel and insert it into the ProductsViewModel array.

When I clone using:

ko.mapping.fromJS(ko.toJS(itemToCopy));

It doesn't appear to copy correctly - the prices observable array, isn't populated with ProductPriceViewModels - just Object

Here's the view models

var ProductsViewModel = function() {
    var self = this;

    self.products = ko.observableArray([new ProductViewModel()]);

    self.addNewProduct = function() {
        self.products.push(new ProductViewModel());
    };

    self.duplicateProduct = function() {
        var itemToCopy = ko.utils.arrayFirst(self.products(), function(item) {
            return item.visible();
        });

        //if i look at itemToCopy.prices() it is an array of ProductViewModel

        var newItem = ko.mapping.fromJS(ko.toJS(itemToCopy));
        //if i look at newItem.prices() it is an array of Object

        self.products.push(newItem);
    };
};

var ProductViewModel = function() {
    var self = this;

    self.name = ko.observable();
    self.visible = ko.observable(true);

    self.prices = ko.observableArray([new ProductPriceViewModel()]);

    self.addPrice = function() {
        self.prices.push(new ProductPriceViewModel());
    };
};

var ProductPriceViewModel = function() {
    var self = this;

    self.name = ko.observable();
    self.price = ko.observable();
};

Upvotes: 1

Views: 2181

Answers (1)

Alex
Alex

Reputation: 38529

I solved this by passing in a mapping configuration like this:

var mapping = {
    'prices': {
        create: function (options) {
            return new ServicePriceViewModel(options.data);
        }
    }
};

on

var newItem = ko.mapping.fromJS(ko.toJS(productToCopy), mapping);

and changing my ProductPriceViewModel to accept data as a parameter:

var ProductPriceViewModel = function (data) {
    var self = this;

    self.name = ko.observable();
    self.description = ko.observable();
    self.price = ko.observable();
    self.priceIsFrom = ko.observable();

    if (data)
        ko.mapping.fromJS(data, {}, this);
};

Upvotes: 1

Related Questions