Dan Dinu
Dan Dinu

Reputation: 33388

Knockout binding: how to update value of an object stored in a observableArray()?

I'm at the "hello world" stage with knockout.js and data-binding.

I can't find the right way to bind and update a member value of an object which is stored in an observableArray.

Binding works first time, but then it doesn't update itself in the webpage.

Here's what i'm trying to do:

<div class="row" data-bind="foreach:chains">
    <div class="col-md-12">
        <h3>Obj id is <span data-bind="text: id"></span> </h3>
        <span data-bind="text: message"></span>         
        </div>
    </div>

javascript part:

(function () {
  var Chain = function (chainId) {
    var self = this;
    self.id = chainId;
    self.message = "N/A";
    // etc. (more memberS)
};


var Model = function() {
    var self = this;
    self.chains = ko.observableArray();
};

 Model.prototype = {
    updateChains: function(updatedChains) {
         // here chain values are updated, in words:
         // if chain does not exist then create it and add it to self.chains
         // self.chains.push(newChain); 
         // otherwise update chain.message as:
         // existingChain.message = updatedMessage;
   }

var model = new Model();

$(function() {
    ko.applyBindings(model);
});
}());

I debugged the code and everything is fine on the update part, the message gets a new value, but it's not visible in the UI (it remains "N/A"). It seems that i'm doing something wrong in the binding.

I tried several other ways but failed each time.

How can I achieve this?

Upvotes: 0

Views: 930

Answers (2)

Timothy Shields
Timothy Shields

Reputation: 79461

From the Knockout page on Observable Arrays:

Key point: An observableArray tracks which objects are in the array, not the state of those objects

Simply putting an object into an observableArray doesn’t make all of that object’s properties themselves observable. Of course, you can make those properties observable if you wish, but that’s an independent choice. An observableArray just tracks which objects it holds, and notifies listeners when objects are added or removed.

If you want the message on a Chain to be observable:

var Chain = function (chainId) {
    var self = this;
    self.id = chainId;
    self.message = ko.observable("N/A");
    ...
};

Then, when you want to set the message on an existing Chain you need to do this:

existingChain.message(updatedMessage);

Not this:

existingChain.message = updatedMessage

Upvotes: 1

Doc
Doc

Reputation: 81

Observable arrays don't track their contents' state, only when the array itself is modified.

Documentation (second paragraph)

One way to achieve your goal would be to have the members of your Chain class also be observable:

var Chain = function (chainId) {
    var self = this;
    self.id = chainId;
    self.message = ko.observable("N/A");
    // etc. (more members)
};

Your update function would then be setting the observable in the found object:

self.chains()[foundIndex].memberToUpdate(newValue)

Upvotes: 1

Related Questions