简体   繁体   中英

knockoutjs deep copy observable array

I have an obeservable array in Knockout, say data that contains objects with observable properties. In one part of my application I want to allow users to add to this array and ultimately mess about with it, but if they cancel to revert the array to the original state.

One solution I though of is to create a copy called dataCopy that replaces the original array in the event of cancellation, but this only creates another pointer to the same underlying data, so it will also reflect the changes that were made which is not what I want. I've tried converting it to javascript, via ko.toJS(data) and this creates a js array of the data, however all of the objects lose their observable properties and when I re-create the data using ko.observableArray(dataCopy) the app falls over as the properties of the objects are no longer observable.

How can I create a clone of a knockout array rather than another pointer?

This is an example of how you could achieve this using the ko mapping plugin for deeply copying your observable arrays. I doubt any other method of copying would work for you such as .slice or ko.toJS since as you mentioned you want a deep copy which goes as far as the underlying object's observable propertieš.

The important part here is the function :

function obsArrDeepCopy(from, to) {
  ko.mapping.fromJS(ko.toJS(from), {}, to);
}

Which will do the deep copy by first converting the source array to a plan JS array and then populate the target array converting to observables the underlying object properties.

Full working example:

 function Person(name) { this.name = ko.observable(name); } var viewModel = { people: ko.observableArray([ new Person("Annabelle"), new Person("Bertie"), new Person("Charles") ]), peopleCopy: ko.observableArray(), newName: ko.observable(''), addPerson: function() { this.peopleCopy.push(new Person(this.newName())) }, commit: function() { obsArrDeepCopy(this.peopleCopy, this.people) }, cancel: function() { obsArrDeepCopy(this.people, this.peopleCopy) }, }; ko.applyBindings(viewModel); obsArrDeepCopy(viewModel.people, viewModel.peopleCopy); function obsArrDeepCopy(from, to) { ko.mapping.fromJS(ko.toJS(from), {}, to); } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script> <h2> Initial </h2> <ul data-bind="foreach: people"> <li> <span data-bind="text: name" /> </li> </ul> <br/><br/> <h2> Copy </h2> <ul data-bind="foreach: peopleCopy"> <li> <span data-bind="text: name" /> </li> </ul> <input type="text" data-bind="textInput: newName" /> <button type="button" data-bind="click: addPerson"> Add </button> <br/><br/> <button type="button" data-bind="click: commit"> Commit </button> <button type="button" data-bind="click: cancel"> Cancel </button> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM