waxwing
waxwing

Reputation: 18783

In knockout.js, is it possible to use a dynamic binding value?

In knockout.js, is it possible to let the right-hand-side of a binding (the value of the binding) be dynamic? For example,

<input data-bind="value: dynamicBinding()"/>
<script type="text/javascript">
var vm = {
   dynamicBinding : function() {
       return "foo().bar";
   },
   foo : ko.observable({
       bar : ko.observable("hi");
   }
};
ko.applyBindings(vm);
</script>

the result should be that the the dynamicBinding function is executed while applying the bindings and the resulting string is used as the binding. The input element should be bound to foo().bar, which is the observable with the value "hi".

If you wonder why I would want this, I am trying to render a dynamic table with knockout, where both the rows and the columns are observableArrays, and I want to allow the column definitions to contain the expression of the binding for that column. I.e., I want to be able to do this:

<table data-bind="foreach: data">
  <tr data-bind="foreach: $root.columns">
    <td data-bind="text: cellValueBinding()"></td>
  </tr>
</table>
<script type="text/javascript">
var vm = {
   data: ko.mapping.fromJS([
     {title: "Brave New World", author: { name : "Aldous Huxley" },
     {title: "1984", author: { name : "George Orwell" },
     {title: "Pale Fire", author: { name : "Vladimir Nabokov" }]),
   columns: ko.observableArray([
     {header: "Title", cellValueBinding: function () { return "$parent.title"; }}, 
     {header: "Author", cellValueBinding: function () { return "$parent.author().name"; }}
   ])
};
ko.applyBindings(vm);
</script>

As you can see from the example, the column definition knows how to extract the value from the data. The table markup itself is more or less a placeholder. But as far as I can tell, this does not work, due to the way knockout processes the bindings. Are there any other options available?

Thanks.


Solution: I ended up using Ilya's suggestion - I can let cellValueBinding be a function that accepts the row and column as arguments, and returns an observable. This technique is demonstrated in this fiddle.

Upvotes: 2

Views: 2528

Answers (1)

Ilya
Ilya

Reputation: 29731

Use ko.computed for it.
Look on example
JSFiddle
EDIT
In your second example, you can pass $parent value ti the function

<td data-bind="text: cellValueBinding($parent)"></td>  

and in model

{header: "Title", cellValueBinding: function (parent) { return parent.title; }},
{header: "Author", cellValueBinding: function (parent) { return parent.author().name; }}

JSFiddle

Upvotes: 2

Related Questions