0
votes

I'm using KnockoutJs 2.2. I have a record which can have zero-to-many category associations. However, I'm finding that KnockoutJs does not actually bind the value to the items inside the record's categories array.

The array of categories are {id, name} objects. This is derived from a lookup list.

self.categories = ko.observableArray([{id:1,name:'Test1'},{id:2,name:'Test2'}]);

On my view model, I have a record object. One of the fields on this object is categories (observableArray).

categories: ko.observableArray([])

The record object is called "r" on the viewmodel for brevity in the bindings.

<div class="yui3-u-4-5">
    <!-- ko foreach: r.categories-->
    <select data-bind="options: $parent.categories, optionsCaption:'-', 
optionsValue:'id', optionsText:'name', value:$data" />
    <div class="del" data-bind="click: $parent.removeCat" />
    <br />
    <!-- /ko -->
    <button data-bind="click: addCat">Add category</button>
</div>

When the user adds or removes a category, the following code is called:

self.removeCat = function (data) {
    self.r.categories.remove(data);
};

self.addCat = function () {
    self.r.categories.push(ko.observable(null));
} 

Basically, what happens is that when a category is added into the self.r.categories array, and then you select a category from the drop down, the selected item's value is not bound to the observable inside the array ($data). The array values remain null.

I have re-created the problem here: http://jsfiddle.net/fxXsq/

Maybe I should be doing this an alternative way?

thanks for your help Kris

1

1 Answers

1
votes

You should not be adding actual new empty observables to your observable array like this.

self.addCat = function () {
    self.r.categories.push(ko.observable(null)); 
} 

Furthermore, if you want the Id and Name properties of your objects to be observable, you'll need a model for them

self.addCat = function () {
    self.r.categories.push(new Category(null, self));
};

function Category(data, parent) {
   var self = this; 
   self.Id = ko.observable(-1);
   self.Name = ko.observable('');

   self.load = function(data) {
       if (data) {
           self.Id(data.Id);
           self.Name(data.Name);
       }
   }
   self.load(data);
}

This is my general template I apply to all my models to better support deferred binding and flexibility.

Now you would have an observableArray r that contains Category objects with observable properties.