Getting two way binding on $data inside a template

5.7k views Asked by At

I am trying to setup generic Knockout templates that can be toggled between edit and readonly mode based on data type. If you've ever used ASP.NET's dynamic data: it's like their field templates. For example:

<script type="text/html" id="text">
    <!-- ko if: $root.editable -->
        <input type="text" data-bind="value: $data" />
    <!-- /ko -->

    <!-- ko ifnot: $root.editable -->
        <span data-bind="text: $data"></span>
    <!-- /ko -->
</script>

This is used like this:

<label><input type="checkbox" data-bind="checked: editable" /> Editable</label>

<p>Name: <input data-bind="value: name" /></p>
<p>Name2: <span data-bind="template: { name: 'text', data: name }"></span></p>

With the following view model:

    var viewModel = {
        name: ko.observable("Brian"),
        editable: ko.observable(true)
    };

The idea is to be able to use templates at the field level like in the "Name2" example, instead of explicit elements/controls. This allows entire forms to be easily toggled between edit and read mode without having large sections of mostly duplicated markup. This also allows reuse of common data type editing/display markup, for example using datepickers for date fields, etc.

The Problem
The $data pseudo variable inside the template does not have two way binding. It will reflect the current value in the observable, but changes in the input control will not set the value.

How can I get two way binding on $data?

See also this jsfiddle

1

There are 1 answers

2
RP Niemeyer On BEST ANSWER

The simplest choice is to pass an object to the template binding that allows you to access the actual observable like:

template: { name: 'text', data: {field: name} }

Then, bind against "field" instead of "$data" in your template.

Another thing to consider would be using a function to determine your template, then you can use separate templates for edit/view like:
http://www.knockmeout.net/2011/03/quick-tip-dynamically-changing.html