Golo Roden
Golo Roden

Reputation: 150852

Converting an observable's property in Knockout.js

I have an observableArray of records which I bind using a template binding. This works fine. As I want to keep track of the changes of each of the records, the observableArray consists of observables. This works, too.

What I now want is to convert some of the properties of each record (i.e. of each observable) to a different type.

How should I proceed?

Usually, I could use a computed, but in this case I can not add a single computed observable to the array, as I need multiple of them.

So how do I solve this?

Upvotes: 0

Views: 583

Answers (2)

gbs
gbs

Reputation: 3529

Here is a solution using a view model wrapping each item of the observableArray. And this view model can then contain a computed property.

var ItemViewModel = function (value) {
    this.value = ko.observable(value);
    this.computedValue = ko.computed(function () {
        return this.value() * 2;        
    }, this);    
};

var ViewModel = function (list) {
    var self = this;
    self.list = ko.observableArray([]);                
    ko.utils.arrayForEach(list, function (value) {
         self.list.push(new ItemViewModel(value)); 
    });
};

ko.applyBindings(new ViewModel([1,2,3]));


<ul data-bind="foreach: list">
<li data-bind="text: computedValue"></li>
</ul>

Upvotes: 1

Mark Robinson
Mark Robinson

Reputation: 13278

You could add a function to your view model that takes a parameter which is the item from the observable array. The binding will run the function inside of a dependentObservable, so any observables that have their value accessed will create a dependency.

So, for example, from Ryan Niemeyer's jsFiddle, you can have the following markup:

type "one", "two", or "three": <input data-bind="value: text" /> 
<hr />
<ul data-bind="template: { name: 'itemTmpl', foreach: items }"></ul>

<script id="itemTmpl" type="text/html">
    <li data-bind="text: name, visible: viewModel.shouldThisBeVisible(name)"></li>
</script>​

.. with the view model:

var viewModel = {
    text: ko.observable("one"),
    items: [{name: "one"}, {name: "two"}, {name: "three"}],
};

viewModel.shouldThisBeVisible = function(name) {
    return this.text() === name;
}.bind(viewModel);

ko.applyBindings(viewModel);​

The crucial bit is where the function takes the parameter of 'name'. In your case, this would be an item from your observable array.

Hope this helps.

Upvotes: 1

Related Questions