Using client templates, part 2: Live Bindings

In part 1, we saw how to use DataView to render JavaScript data using a simple template. In this post, we'll see how rich bindings unlock richer scenarios where user changes automatically propagate back to the data and to all UI that is bound to it.

In part 1, we used the simplest type of binding, one-way, one-time bindings. These bindings are created using the {{ expression }} syntax, which is both simple and rich in that it enables arbitrary JavaScript expressions. This is made possible by the fact that templates are compiled by the Ajax framework into a JavaScript function and these bindings get embedded right into that generated function. Because of that, the binding gets evaluated only once, when the template is instantiated.

For more complex scenarios where you need changes to the data to be automatically reflected by the UI or where you need bidirectional bindings, we are also supporting WPF's binding syntax. Let's use that syntax to modify the way the template in part 1 displays a person's name:

<legend>
<
span>{binding FirstName }</span>
<
span>{binding LastName }</span>
</
legend>

In order to be able to make changes to the data, I'll add a second DataView to the page, this one with input fields for the first and last names of each person in the data set:

<table>
  <thead><tr><td>First name</td><td>Last name</td></tr></thead>
  <tbody id="peopleTable" class="sys-template">
    <tr>
      <td><input type="text" sys:value="{binding FirstName}" /></td>
      <td><input type="text" sys:value="{binding LastName}" /></td>
    </tr>
  </tbody>
</table>

And now, without having written a single line of JavaScript code other than the DataView controls instantiation and data property setting, our boring read-only template became read-write. Any time the data in one of the input boxes changes, the binding will pick up the change and propagate it to the data. Our first template, because it was bound to the same data, will also get the changes automatically so that any change here:

ClientTemplateInput

will get reflected here:

TemplatePhotoLegendChanged

as soon as you focus out of the input field. One thing to notice is that even though you can explicitly set the binding direction on a binding, the framework does the right thing here by default by making bindings on input fields bidirectional and bindings on text node values unidirectional.

Oh, one last thing: just for fun, I took the screen shots in Google Chrome, where the new template stuff already works great.

The code in this post uses ASP.NET Ajax Codeplex Preview 2 the Microsoft Ajax Library Preview 6, which you can download here:
http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=16766
http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34488

The sample code for this post can be downloaded from here:
http://weblogs.asp.net/blogs/bleroy/Samples/TemplateLiveBindings.zip
http://weblogs.asp.net/blogs/bleroy/Samples/TemplateLiveBindingsPreview6.zip

UPDATE: fixed the code to use Preview 6 instead of preview 2.

28 Comments

  • Hey,

    Many thanks very interesting article you posted.
    But I was few questions regarding the web service.
    Is it the normal Web Service (.asmx) or a JSon based web service.Another thing if the Web Service fails than How these kind of situations can be manipulated.

    Overall, brilliant.

    Regards,

    Khurram.

  • @Khurram: the service is a normal asmx service, *but* used in JSON mode. In ASP.NET, any web service can be very easily morphed into a JSON service by adding a [ScriptService] attribute. ASP.NET even generates an optional JavaScript proxy (that we're using here) that is accessed using the PeopleIKnow.asmx/js url (notice the /js at the end).
    You can provide callbacks for failures or timeouts of the web service as additional parameters to the service call.

  • @Odegaard: in a one-way/one-time binding, you can do {{ Math.Round(Average) }}, but even with live bindings, you can provide a convert function (and also a convertBack function for two-way): {binding Average, convert=Math.round}.

  • Changing the value in the textbox...it changes the javascript variables held in memory, right? Does the changes propagate to the server (or even the db)? I wouldn't think so. So, how are we to call our script service when a change is made? Are there any hookable event handlers that we can use that give us something like "newValues" and "oldValues" in javascript?

  • Heartattack: that is of course an excellent question. There are mutation events that you can subscribe to on the JavaScript object and I'm going to cover that in the next post. To be clear, you are still using a plain JavaScript object, but we instrument it automatically when you do the binding so that it exposes change events.
    In the next release, we're adding a DataSource control that handles those change notifications automatically and will be able to send them back to the server without requiring that you write any code.

  • Looking good! But!

    I can't figure out the expression syntax to use of if my data item is an an array, as opposed to an object with named fields. In other words, instead of an expression like {{Name}} I would like to use {{[0]}}.

    It looks like the template compiler generates code that evaluates the expression inside of a 'with' block, which seems to break the array indexing inside the expression. So I am currently resorting to a hack: {{ $dataItem[0] }}.

    Is there/will there be an easier way to do this?

  • @John: that is actually pretty uncommon, which is why we're not providing a specific syntax for that. {{ $dataItem[0] }} is actually not a hack at all but the supported way of doing that.

  • Hi Bertrand,

    I only just got round to digesting these two posts on client templates. I think it is a necessary feature to aid client development, which when doing anything non-trivial can quickly become overly complex. I'm not sure I'm 100% happy with the template syntax but I can't think of any improvements and it sounds like you guys have debated it a lot! The actual binding syntax looks intuitive.

    I've recently completed a project that required a certain degree of client side functionality that we don't get a great deal of help with when using ASP.NET. Among that functionality was a 'right-click-context-menu' for manipulating one-or-more rows of tabular data. I used a jQuery plugin to get the context menu up and running quickly. The menu options called back to an ASP.NET web service (script service?).

    The approach worked really well for us. However, if data was updated on the server and the change needed to be reflected on the UI then we were forced to round-trip the current page, to keep view state updated.

    I would be interested to know how the client templates play with view state? If I was to guess I would say that with the Web Forms model there will always be the problem of keeping view state in-sync.

    Perhaps I am thinking about this all wrong though. I guess a more 'Web 2.0' approach would be to render a 'web form' (aka ASP.NET page) and leverage the power of client script to render out portions of the page and communicate changes back to the server. Therefore the page state is stored on the client and NOT on the server, hence removing the need for view state (?).

    I look forward to your comments.

  • When pondering how extensively to use client templates, a big issue is search engine optimization (SEO). It seems to me that any data placed in the page using {{...}} will be invisible to search engines. This seems like a major restriction of the approach, limiting it to only minor parts of the page - basically anything that is very dynamic such as today's date, the current user name and so on.

    I don't see any easy way around this problem... A pity. I was looking forward to having a lovely architecture where the DAL and business logic are all buried under a set of JSON data services and all the view layer is client-template HTML.

    Or am I missing something here?

  • @Oren: what you're saying applies not only to client templates but simply to all Ajax applications. For all resources that must be optimized for searching, all the info must be available from a simple GET request in the first place, which means that it has to be formatted on the server. Just don't render on the client what must be available on the GET request. That still leaves a lot of room for Ajax to improve the usability of applications.

  • I agree, the search engine problem holds for all Ajax code. It is just that client templates are very tempting for MVC architecture - move the V layer into the browser where it belongs. Alas, the SEO problem puts a strong limit on this.

    A common workaround used by Ajax applications is to place the data in some invisible div element for the search engine. This means sending the same data twice into the page, or using DOM operations to access the data from the invisible div.

    The latter is an interesting option, but it has two problems - first, creating data services that send the data as search-engine-friendly HTML is not automatic, while sending JSON/XML is, and second extracting the data from the DOM is awkward and inefficient compared to accessing JSON data.

    Of course, one could envision some extension to ADO and client templates that would address both problems (except the efficiency issue perhaps, but browsers JS/DOM implementations are getting faster...). But I guess this is such a twisted solution that making it mainstream is not in the cards :-)

  • Hi Bertrand,

    I've just read these posts and your MSDN magazine article on AJAX 4.0 and i'd like to congratulate you on your innovative approach to client side templating, looking forward to rolling it out.

    Also i've noticed you weathering a fair share of negativity in various forums lately and i've got to say i'm pretty impressed with how you've kept it professional, kudos. Some of the SharePoint boys could take a few pointers from you - sorry, couldn't help myself :)

  • @Oren: you make really good points here. We actually have a couple of prototypes along those lines. In particular, we have a server-side DataSource control that renders its data under the form of HTML tables, with a client-side parser that transforms that into JS data objects that can then be exploited client-side. You've got to be careful about how you hide that rendering of the data though as search engines tend to not index something hidden and can even consider that to be spam.
    We actually alluded to that kind of approach in our roadmap document (publicly available from CodePlex). This kind of server-side integration is currently on the back burner though.

    @Derek: thanks for the kind words.

  • I see that this usage is really nice. What about binding visible template without creating a new instance of it. For example 3 inputs for FirstName, LastName and Age with Save Button. Is it possible to use {binding } with the twoWay in this case and then eventually save the result?

  • @gramic: You can create the Binding class from code and achieve that result. I'll also ask Dave whether that can be done declaratively by activating that part of the DOM. I'm not sure. Stay tuned.

  • @gramic: blogged... http://weblogs.asp.net/bleroy/archive/2008/10/14/hack-using-live-bindings-outside-templates.aspx

  • How do you 2-way bind a date? When I utilize this AJAX Client Templating to bind to a textbox and add the jQuery Datepicker, it goes all nuts. Changing the Date on the textbox changes it to a string and doesnt really 2-way bind correctly. Is there some Datepicker associated with this library I can use to test so that it maps to and from the Javascript Object seamlessly?

  • Hi Bertrand I have a couple of questions regarding what I should invest my time learning.

    Should I go down the route of Ajax 4.0 or with Microsofts support for jQuery and from what I have seen from buying the book jQuery in Action, the ease at which you can use AJAX with jQuery. Also the use of jTemplates for dong the same as live bindings.
    Which way should I go? Or am I being naive and really Ajax 4 has a lot more to offer.

  • @Chris: it's actually not one or the other: jQuery has great selector support, which Microsoft Ajax does not, and Microsoft Ajax has a great component model, globalization and localization support, live bindings, ASP.NET integration and lots of other things that jQuery does not. I use both on many of my projects. A few things to consider: only the core jQuery file is supported by Mirosoft (hence jTemplate is not supported). Also, jTemplate does *not* do what live bindings are doing.

  • Hi,
    My question is similar to that asked by 'John Lewicki'. I am trying to bind a dataitem which is basically a javascript object. I want to refer its fields inside my templates. Like :

    {{ dataitem.subitem }}

    Is this possible ?

    Can it be made possible in future by allowing child templates, that use 'dataitem' from the parent parent as source?

    Also, is it possible to attach a client side callback function (just like the ItemDataBound) which can passed the 'dataitem' object as parameter.

  • @geek111222: sure, you can do all that already.
    The syntax in {{ }} is JavaScript so you can reference *any* object from there. For the current dataitem, you don't even need to dereference and you can do {{ subitem }} directly. But you could also have a global object and reference that.
    Nested templates are also already supported. You can reference the parent template's data item using $parentContext.dataItem.
    The DataView exposes an itemCreated event that gets a TemplateContext in the event arguments. You can get to the data item by doing args.get_templateContext().get_dataItem().
    See http://weblogs.asp.net/bleroy/archive/2008/11/28/instantiating-components-on-template-markup.aspx for an example of that.

  • Hi,

    how this is different from JQuery based on the performance ?

    Thanks ,
    Thani

  • @Thanigainathan: well, jQuery does none of that so it's a tough question to answer...

  • Hi Bertrand,
    None of these work with preview 6 of same files. Please let me know if there any significant changes in syntac and what could be going wrong here.

  • @Monalisa1: I updated the post to use Preview 6.

  • Apologies if I'm missing something obvious but I can't figure out how to use a client template with an input such as a SELECT drop-down, ie where there's no "value=" attribute on the tag. I would like to bind data to a mix of inputs so the user can then edit the data, including SELECTs. I can't find any examples on the net of using templates with this sort of input field. Thanks in advance.

  • @Peter: I wrote a post that hopefully answers your question... http://weblogs.asp.net/bleroy/archive/2010/03/11/binding-a-select-in-a-client-template.aspx

  • That's great. Many thanks for taking the time to write a post to explain it.

Comments have been disabled for this content.