Reputation: 1645
Let me preface this question by stating that I have only started working with the Knockout library yesterday afternoon so this quite possibly could be a factor in this issue.
Before I get into the code, I am trying to create a model that a Competition object which has a Name property and a Criteria property which is a collection of Criterion objects. A Criterion object has a PrimaryDescription and SecondaryDescription property.
Here is what I have so far:
function Competition(name, criteria)
{
var self = null;
self = this;
self.Name = ko.observable(name);
self.Criteria = criteria;
return;
}
function Criterion(id, primaryDescription, secondaryDescription)
{
var self = null;
self = this;
self.Id = id;
self.PrimaryDescription = ko.observable(primaryDescription);
self.SecondaryDescription = ko.observable(secondaryDescription);
return;
}
In the view model, I have a Competition property that is set up like this:
self.Competition = ko.observable(new Competition('Competition 1', ko.observableArray([new Criterion(-1, 'Criterion 1', 'Criterion 1'), new Criterion(-1, 'Criterion 2', 'Criterion 2')])));
When the page loads, a binding to Competition().Criteria() works as expected.
In the view model, I have added the following:
self.addCriterion =
function ()
{
self.Competition().Criteria().push(new Criterion(-1, '???', '???'));
alert(self.Competition().Criteria().length);
return;
}
When I call this method, the new element gets added to the array and the array length is accurately reflected. However, the binding is not updated. I messed around a bit and changed the line in the Competition model part from "self.Criteria = criteria" to "self.Criteria = ko.observableArray(criteria)". When I do this and call the addCriterion method, the new element is added to the array and the binding updates the UI but the length of the array is reported as zero.
Since I can only get this working halfway, this tells me I am doing something wrong. What am I missing?
Many thanks in advance to whoever can steer me in the right direction.
Upvotes: 1
Views: 193
Reputation: 239440
First off, not everything needs to be an observable. In fact, things should only be an observable if you truly need that functionality. There's a ton of overhead involved in constructing, initializing, and updating observables.
You haven't shown your view model (the thing you register with ko.applyBindings
), but typically, your view model will just be the thing you're interacting with, not some abstraction over that. In other words, if your view is centered around the concept of a "Competition" then Competition
, itself, would be your view model for the page.
Nevertheless, don't create an observable of an object. Knockout can't detect changes within an object, only changes to the whole object, i.e. you store a completely new instance of Competition
in the self.Competition
observable. As a result, just treat it as a simple JS var on your view model:
self.Competition = new Competition( ... );
Then if you want to reference an observable inside that, you just chain it like normal in JS: self.Competition.SomeObservable()
.
@jaux is right about the reason for your specific issue.
Upvotes: 2
Reputation: 8986
You should call self.Competition().Criteria.push
instead of self.Competition().Criteria().push
, because self.Competition().Criteria()
will get you the original ordinary array.
Upvotes: 2