Hack: using live bindings outside templates

A comment on this post is asking whether it is possible to create bindings outside of a template. The point of doing that is that you don’t necessarily want to render a template just to set-up a few bindings.

Well, bindings are really implemented by a component, Sys.Binding, and a markup extension, which instantiates that component through the convenient {binding foo} syntax.

While the markup extension is only understood by the template engine, the component can be instantiated like any other component, through $create or declaratively (thanks to Dave for pointing me to how this can be done).

Here is a sample page where two bindings are created (imperatively and declaratively) to bind a span’s text (imperatively) and an input’s value (declaratively) to the same plain JavaScript data object. Modifying the value in the input changes the data object, which in turn changes the span that is also listening to it.

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Binding</title>
    <script type="text/javascript">
        var data = { answer: 42 };

        function pageLoad() {
            $create(Sys.Binding, {
                target: $get('answerDisplay'),
                targetProperty: 'innerText',
                source: data,
                path: 'answer',
                mode: Sys.BindingMode.oneWay
            });
        }
    </script>
</head>
<body xmlns:sys="javascript:Sys"
      xmlns:binding="javascript:Sys.Binding"
      sys:activate="*">
    <form id="form1" runat="server">
    <asp:ScriptManager runat="server" ID="SM1">
        <Scripts>
            <asp:ScriptReference
                Path="~/Script/MicrosoftAjaxTemplates.js" />
        </Scripts>
    </asp:ScriptManager>
    <div>
        <span id="answerDisplay"></span><br />
        <input type="text" id="answer"
            sys:attach="binding"
            binding:target="{{ $get('answer') }}"
            binding:targetproperty="value"
            binding:source="{{ data }}"
            binding:path="answer"
            binding:mode="{{ Sys.BindingMode.twoWay }}" />
    </div>
    </form>
</body>
</html>

Not quite as convenient as being able to directly use the markup extension but it gets the job done. Please also be aware that the overhead in rendering a template is very small and the convenience of the markup extension may be preferred over this. Here is the same page using a DataView:

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Binding</title>
    <script type="text/javascript">
        var data = { answer: 42 };
    </script>
</head>
<body xmlns:sys="javascript:Sys"
      xmlns:dataview="javascript:Sys.UI.DataView"
      sys:activate="*">
    <form id="form1" runat="server">
    <asp:ScriptManager runat="server" ID="SM1">
        <Scripts>
            <asp:ScriptReference
                Path="~/Script/MicrosoftAjaxTemplates.js" />
        </Scripts>
    </asp:ScriptManager>
    <div sys:attach="dataview" dataview:data="{{ data }}">
        <span id="answerDisplay">{binding answer }</span><br />
        <input type="text" id="answer" value="{binding answer}"/>
    </div>
    </form>
</body>
</html>

9 Comments

  • So are you guys planning on adding the support to the new engine so that the processing of the markup isn't limited to templates only? Ya know, how the "old" XMLScript used to process markup for even static content?

    Would seem like a very strange decision NOT to since it would force this half JS/half markup world... or force everyone to put a dataview around their whole page to make it a template.

    Curious,
    Drew

  • @Drew: no, that would kill perf. Putting a dataview around your whole page would be just as stupid as putting an update panel around a whole page...

  • thanks for the article.i am digesting it! ;)

  • Using markup that way is much better then using Sys.Binding class from code. I saw that it is possible to set sys:activate="*" at the parent tag of the template.

    Even that I thought about a way to data bind without creation of any template compilation but just parse properties.

    As in your example: the DOM elements are already created and the data binding markup is in the properties too. Maybe just tracing the DOM properties and do the Data Binding will suffice and will not take the performance away.

  • @gramic: just looking at all attributes on all elements will kill initial performance. The way activate works, it only has to look at one thing on each element: sys:attach. I hope this clarifies.

  • @Drew: I'm certainly not going to smack you but the exact code that is in your comment will work just fine provided you write the button and textbox controls (or re-use the old ones from Futures). The sys:attach attributes will work just anywhere and once it's been parsed the rest of the tag is fully activated. It's a binding on its own that will need to be in a template.

  • Bertrand,

    Yeah, a coworker gave it a shot shortly after he saw my comment and we saw that it worked. I deserve a smack for not trying it before asking. :P It's just that it's not shown anywhere in the Road Map being used that way and it's always talked about in the context of templates so I thought maybe we regressed somehow.

    Anywho, glad to see it works and looking forward to new info @ the PDC next week!

    Cheers,
    Drew

  • How do you 2-way bind a date to a textbox control? 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?

  • @Corey: I haven't tried the jQuery Datepicker but you can absolutely 2-way bind a textbox to a date. The trick is to use a convert function and a convertBack function on the binding to go from date to string and from string to date. The functions can use String.format and Date.parseLocale. We do have a date picker in the Ajax Control Toolkit: the Calendar behavior. http://www.asp.net/AJAX/AjaxControlToolkit/Samples/Calendar/Calendar.aspx

Comments have been disabled for this content.