简体   繁体   中英

How to assign a KnockoutJs observable to another observable?

I have a model defined as:

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

    self.Item = ko.mapping.fromJS(new Item());
    self.ItemList = ko.observableArray();
};

var Model = new TestModel();
ko.applyBindings(Model);

After an AJAX call I fill the array with:

ko.mapping.fromJS(data, {}, Model.ItemList);

The array is displayed in the screen and when the user selects an item, a modal dialog is opened to edit that item. The same modal dialog can be opened to add a new item. That modal has a data-bind="with: Item" , so I can do something like this:

function add() {
    ko.mapping.fromJS(new Item(), {}, Model.Commission); //Empty object
    $('#dialog').dialog('open');
};

function saveAdd() {
    //Clone the properties...
    Model.ItemList.push(ko.mapping.fromJS(ko.mapping.toJS(Model.Item)));
}

function edit(i) {
    //Clone properties!
    ko.mapping.fromJS(ko.mapping.fromJS(ko.mapping.toJS(Model.ItemList()[i])), {}, Model.Item);
    $('#dialog').dialog('open');
}

function saveEdit(i) {
    //Clone properties!!!!
    Model.ItemList()[i] = ko.mapping.fromJS(ko.mapping.toJS(Model.Item));
}

I want to avoid cloning the properties every time I need to assign the values of one observable to another one. I understand that if I manage to tell Knockout that the Model.Item is some Model.ItemList()[i] , the objects references should make sure the changes in the UI reflect directly to my observableArray item, but I cannot just assing it as Model.Item = Model.ItemList()[i]; because that breaks the binding between the original Model.Item object and the view [*1].

Is there a way to assign an observable to another observable that's binded to the view, and maintain the references?

Failing to do that, is the a better way to do this? Basicaly a page where you store the list of items in an observableArray and then add/edit in another piece of HTML.

Edit: Explanation for [*1]

I cannot find the stackoverflow question where this was explained, but it was something like this:

When we do ko.applyBindings(Model); , the observable objects inside Model get binded to the view. At this point the object referenced by Model.Item is binded, so if I do Model.Item = Model.ItemList()[i]; the new object being referenced by Model.Item is not binded to anything. The original object (in memory) is still the one binded to the view, just that there are no references to it now.

If you make Model.Item an observable, with the mapped object inside of it, then you can set the observable's contents to the new item. The reference to the observable made by knockout remains intact because you're just updating the contents and not the property itself.

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

    self.Item = ko.observable(ko.mapping.fromJS(new Item()));
    self.ItemList = ko.observableArray();
};

...
Model.Item(Model.ItemList()[i]);

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