jQuery templates plugin: how to create two-way binding?
Asked Answered
L

2

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?

Lactate answered 23/2, 2011 at 20:41 Comment(4)
Take a look at the data linking plugin: github.com/jquery/jquery-datalinkHike
I know about this plugin, but the problem is - I can't use it as I don't have individual html elements generated by the templateLactate
your json is not correct: {member: "value"} ;)Hike
take a look knockoutjs (observableArray), repeated items is a common task any data binding library should address, I'm surprised it's not yet done in datalink ;)Hike
G
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>
Gonfanon answered 23/2, 2011 at 21:0 Comment(11)
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...Lactate
You should really check out the knockout stuff. MVVM seems to be the way to go with AJAX based HTML applications.Gonfanon
Serge, can you show me how to use knockout for two-way binding with my particular example?Lactate
Just so I understand, knockout also provides its own templating engine, right? So I could replace MS's tmpl plugin with it?Lactate
Andrey, if you still want it, i can give you an example after i get out of work tonight.Gonfanon
As far as templating, knockout doesn't have it's own template engine, it uses jquery.tmpl by default.Gonfanon
@Serge: I would appreciate if you could give me an example when you have time! Thanks a lot!Lactate
Alright, example posted. I added a span and an input field for each record so you can see the data binding at work.Gonfanon
@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 wellBlowy
@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.Gonfanon
@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... thats why i was thinking if some how we can access the html control value from code behind then its very easy to handle the two way binding with Data link Plugin as wellBlowy
S
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);
});
Schism answered 23/2, 2011 at 20:58 Comment(3)
No, I'm talking about updating template data object, when html fields are updated by userLactate
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.Gonfanon
@Serge - the console log is deceiving. clear the console between each change and you will see the object change.Schism

© 2022 - 2024 — McMap. All rights reserved.