2

I started using jQuery templates plugin (the one Microsoft created), but now I face this problem: the template is for a bunch of forms bound to an array of objects; when I change something on one of the forms, I want the bound object to update and I can't figure out how to automate that.

Here's a simple example (real life template and object are much more complex) :

<!-- Template -->
<script type="text/html" id="tmplTest">
    <input type="text" value="${textvalue}"/>
</script>

<!-- object to bind -->
<script type="text/javascript">
    var obj = [{textvalue : "text1"},{textvalue : "text2"}]

    jQuery("#tmplTest").tmpl(obj)
</script>

This will populate two textboxes, each bound to a value from corresponding object. Now, if I change a value in one of the textboxes, I need to update corresponding data object's value. Any idea how to do that?

Andrey
  • 20,487
  • 26
  • 108
  • 176

2 Answers2

9

jQuery template doesn't actually implement two-way data binding, but another Microsoft developed jQuery plugin does. This Scott Guthrie post actually covers both the tmpl plug in and Data Linking plugin. Scroll down to "Support for Client Data-Linking" where Scott goes into detail on how the Data Linking plug in works.

However, for two way data binding, i find the knockoutjs extension to be much better and cleaner. The declarative syntax keeps the markup clean and the custom data binding overrides allow for a multitude of applications. Finally the mapping plugin is pretty great for processing JSON from the server into binding. Finally knockoutjs also has bindings based on tmpl plugin as well.

Good luck with your problem.

EDIT: updated Code Example

Scrips required:

<script src="/Scripts/jquery-1.5.0.min.js" type="text/javascript"></script>    
<script src="/Scripts/jquery.tmpl.js" type="text/javascript"></script> 
<script src="/Scripts/knockout.js" type="text/javascript"></script>      
<script src="/Scripts/knockout.mapping.js" type="text/javascript"></script>    

Then here is the meat and potatoes

<!-- div for loading the template -->
<div data-bind='template: { name: "tmplTest", foreach: viewModel.list }'>    
</div>

<!-- your template -->
<script type='text/html' id='tmplTest'>
    <div>        
        <span data-bind='text: textvalue, uniqueName: true'></span>
        <input data-bind='value: textvalue, uniqueName: true, valueUpdate:"afterkeydown"'/>
    </div>
</script>

<script type='text/javascript'>
       var viewModel = ko.mapping.fromJS(
        {            
            list:[  { textvalue: "text1" },
                    { textvalue: "text2"}   ]
                }); 

        $(function() {
            ko.applyBindings(viewModel);
        });
 </script>
Sergei Golos
  • 4,342
  • 1
  • 18
  • 21
  • I've read ScottGu's article (thats' how I found out about the templating plugin in the first place), but what's he describing in the article and the actual implementation of the plugin are two different things. They haven't integrated two-way binding into the templating engine (adding {link field}) - I guess it's stayed as proposal only... – Andrey Feb 23 '11 at 21:08
  • You should really check out the knockout stuff. MVVM seems to be the way to go with AJAX based HTML applications. – Sergei Golos Feb 23 '11 at 21:11
  • Serge, can you show me how to use knockout for two-way binding with my particular example? – Andrey Feb 23 '11 at 21:18
  • Just so I understand, knockout also provides its own templating engine, right? So I could replace MS's tmpl plugin with it? – Andrey Feb 23 '11 at 21:29
  • Andrey, if you still want it, i can give you an example after i get out of work tonight. – Sergei Golos Feb 23 '11 at 21:32
  • As far as templating, knockout doesn't have it's own template engine, it uses jquery.tmpl by default. – Sergei Golos Feb 23 '11 at 21:32
  • @Serge: I would appreciate if you could give me an example when you have time! Thanks a lot! – Andrey Feb 23 '11 at 21:34
  • Alright, example posted. I added a span and an input field for each record so you can see the data binding at work. – Sergei Golos Feb 23 '11 at 22:36
  • @sergei Golobs if we want to access the value of html control in code behind then can we access it by defining the name attribute of an html texbox and then use it in code behind by request?? like Request["textbox1"] ??? if yes that`s mean we can achieve two way binding in Data Link Plugin as well – Siddiq Baig Dec 07 '13 at 18:22
  • @SiddiqBaig, not quite sure what you mean by that. Request["textbox1"] and "code behind" sounds like you are talking about Asp.NET webforms. Knockout is a client side tool. – Sergei Golos Dec 09 '13 at 16:18
  • @Sergei Golos yup you are right i am talking about asp.net webform.. and also i am talking about Data Link Plugin not for Knockout... as Knockout already providing a two binding but Data link plugin is not providing two way binding... that`s why i was thinking if some how we can access the html control value from code behind then it`s very easy to handle the two way binding with Data link Plugin as well – Siddiq Baig Dec 09 '13 at 19:51
0

You could write your own data link. Note: I needed the index to make this work, so I added your data into an array, and put an each in the template. If someone knows how to get the index without using an each please add :) jsfiddle link

<script type="text/html" id="tmplTest">
    {{each inputs}}
    <input type="text" class="datalink" data-key="textvalue" data-index="${$index}" value="${$value.textvalue}"/>
    {{/each}}
</script>
<div id="output"></div>


$.extend(window, {
    data:[
        {inputs: [{textvalue:"text1"},{textvalue:"text2"}]}
    ]
});

$('#output').append($("#tmplTest").tmpl(window.data));

$('#output .datalink').live('change', function(){ // update object on change
    var $this = $(this),
        d = $this.data();
    window.data[0].inputs[d.index*1][d.key] = $this.val();
    console.log(window.data[0].inputs);
});
Josiah Ruddell
  • 29,697
  • 8
  • 65
  • 67
  • No, I'm talking about updating template data object, when html fields are updated by user – Andrey Feb 23 '11 at 21:04
  • Playing around with the jsfiddle, updating the value in the text box doesn't seem to update the value in the JSON array. It seems that the live'change' is never actually being triggered. – Sergei Golos Feb 23 '11 at 22:58
  • @Serge - the console log is deceiving. clear the console between each change and you will see the object change. – Josiah Ruddell Feb 23 '11 at 23:43